interrupt()中断对LockSupport.park()的影响
文章目录
- 原理简单讲解
- 调用park()与unpark()
- park/unpark实现的伪代码
- park/unpark的实验
- interrupt()与park()
- interrupt()实现的伪代码
- interrupt()实验
- sleep()与interrupt()
- sleep()实现的伪代码
- sleep()实验
- wait/join 效果同sleep
- 总结
原理简单讲解
首先声明,本文不会去贴native方法的cpp实现,而是以伪代码的形式来理解这些native方法。
- Thread对象的native实现里有一个成员代表线程的
中断状态
,我们可以认为它是一个bool型的变量。初始为false。 - Thread对象的native实现里有一个成员代表线程是否可以阻塞的许可
permit
,我们可以认为它是一个int型的变量,但它的值只能为0或1。当为1时,再累加也会维持1。初始为0。
调用park()与unpark()
park/unpark实现的伪代码
下面将以伪代码的实现来说明park/unpark的实现。
park() {if(permit > 0) {permit = 0;return;}if(中断状态 == true) {return;}阻塞当前线程; // 将来会从这里被唤醒if(permit > 0) {permit = 0;}
}
可见,只要permit
为1或者中断状态
为true,那么执行park
就不能够阻塞线程。park
只可能消耗掉permit
,但不会去消耗掉中断状态
。
unpark(Thread thread) {if(permit < 1) {permit = 1;if(thread处于阻塞状态)唤醒线程thread;}
}
unpark
一定会将permit
置为1,如果线程阻塞,再将其唤醒。从实现可见,无论调用几次unpark
,permit
只能为1。
park/unpark的实验
public class test3 {public static void main(String[] args) throws InterruptedException {LockSupport.park(); //因为此时permit为0且中断状态为false,所以阻塞}
}
上面程序执行后,程序不会运行结束,main线程阻塞。
原因是,线程默认的permit
是0,中断状态
为false,所以会阻塞当前线程;
。
public class test3 {public static void main(String[] args) throws InterruptedException {LockSupport.unpark(Thread.currentThread()); //置permit为1LockSupport.park(); //消耗掉permit后,直接返回了}
}
上面程序执行后,程序运行结束。
原因是LockSupport.unpark(Thread.currentThread())
执行后,会使得main线程的permit
为1。而park
时发现这个permit
为1时,就会消耗掉这个permit
,然后直接返回,所以main线程没有阻塞。
public class test3 {public static void main(String[] args) throws InterruptedException {LockSupport.unpark(Thread.currentThread());LockSupport.park(); //消耗掉permit后,直接返回了LockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞}
}
上面程序执行后,程序不会运行结束,main线程阻塞。
原因是第二次park
时,permit
为0了,中断状态为false,所以会阻塞当前线程;
。
public class test3 {public static void main(String[] args){Thread main = Thread.currentThread();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("子线程开始睡觉");try {Thread.sleep(1000);//睡一下保证是在main线程park后,才去unpark main线程} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+"抛出了中断异常");}System.out.println("子线程睡醒了,开始unpark main线程");LockSupport.unpark(main);}}).start();LockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞//被子线程unpark后,从上一句被唤醒,继续执行。此时permit还是为0,中断状态为false。LockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞}
}
上面程序执行后,程序不会运行结束,main线程阻塞。
这个程序同上,只是之前的版本都是先unpark
,再park
。现在保证是,main线程先park
后,再去unpark
main线程。
interrupt()与park()
interrupt()实现的伪代码
interrupt(){if(中断状态 == false) {中断状态 = true;}unpark(this); //注意这是Thread的成员方法,所以我们可以通过this获得Thread对象
}
interrupt()
会设置中断状态
为true。注意,interrupt()
还会去调用unpark
的,所以也会把permit
置为1的。
interrupt()实验
public class test3 {public static void main(String[] args) throws InterruptedException {Thread.currentThread().interrupt();LockSupport.park(); //消耗掉permit后,直接返回了}
}
上面程序执行后,程序运行结束。因为park
执行时permit
为1,直接返回了。
public class test3 {public static void main(String[] args) throws InterruptedException {Thread.currentThread().interrupt();LockSupport.park(); //消耗掉permit后,直接返回了LockSupport.park(); //因为中断状态 == true,直接返回了LockSupport.park(); //同上}
}
上面程序执行后,程序运行结束。马上无论怎么park
都无法阻塞线程了,因为此时线程的中断状态
为true,函数直接返回了。
public class test3 {public static void main(String[] args) throws InterruptedException {Thread main = Thread.currentThread();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("马上开始睡觉");try {Thread.sleep(1000);//睡一下保证是在main线程阻塞后,才去中断main线程} catch (InterruptedException e) {e.printStackTrace();}System.out.println("睡醒了,开始中断main线程");main.interrupt();}}).start();LockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞//被子线程中断后,从上一句被唤醒,继续执行。此时permit为0,中断状态为true。LockSupport.park(); //因为中断状态 == true,直接返回了LockSupport.park(); //同上}
}
上面程序执行后,程序运行结束。
这个程序同上,只是之前的版本都是先中断,再park。现在保证是,main线程先阻塞后,再去中断main线程。
sleep()与interrupt()
sleep()实现的伪代码
sleep(){//这里我忽略了参数,假设参数是大于0的即可if(中断状态 == true) {中断状态 = false;throw new InterruptedException();}线程开始睡觉; if(中断状态 == true) {中断状态 = false;throw new InterruptedException();}
}
sleep()
会去检测中断状态,如果检测到了,那就消耗掉中断状态后,抛出中断异常。但sleep()
不会去动permit
。
sleep()实验
public class test3 {public static void main(String[] args){Thread.currentThread().interrupt();try {Thread.sleep(1000); // 消耗掉中断状态后,抛出异常} catch (InterruptedException e) {e.printStackTrace();}}
}
上面程序执行后,抛出异常,程序运行结束。
public class test3 {public static void main(String[] args){Thread.currentThread().interrupt();try {Thread.sleep(1000); // 消耗掉中断状态后,抛出异常} catch (InterruptedException e) {e.printStackTrace();}LockSupport.park(); //消耗掉permit}
}
上面程序执行后,抛出异常,程序运行结束。
public class test3 {public static void main(String[] args){Thread.currentThread().interrupt();try {Thread.sleep(1000);//消耗掉中断状态} catch (InterruptedException e) {e.printStackTrace();}LockSupport.park(); //消耗掉permitLockSupport.park(); //因为此时permit为0且中断状态为false,所以阻塞}
}
上面程序执行后,抛出异常,程序不会运行结束。
public class test3 {public static void main(String[] args){Thread main = Thread.currentThread();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("子线程开始睡觉");try {Thread.sleep(3000);//睡一下保证是在main线程sleep后,才去中断main线程} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+"抛出了中断异常");}System.out.println("子线程睡醒了,开始中断main线程");main.interrupt();}}).start();try {System.out.println("主线程开始睡觉");Thread.sleep(5000); //main线程开始睡觉// 当被中断唤醒后,会消耗掉中断状态。唤醒后继续执行} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName()+"抛出了中断异常");}LockSupport.park(); //消耗掉permit后,直接返回了LockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞}
}
上面程序执行后,抛出异常,程序不会运行结束。
这个程序同上,只是之前的版本都是先中断,再sleep。现在保证是,main线程先sleep后,再去中断main线程。
wait/join 效果同sleep
public class test3 {public static void main(String[] args){Thread.currentThread().interrupt();Object lock = new Object();synchronized (lock) {try {lock.wait(); //消耗掉中断状态} catch (InterruptedException e) {e.printStackTrace();}}LockSupport.park(); //消耗掉permitLockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞}
}
上面程序执行后,抛出异常,程序不会运行结束。
public class test3 {public static void main(String[] args){Thread.currentThread().interrupt();Thread thread = new Thread(()->{while (true) {}});thread.start();try {thread.join(); //消耗掉中断状态} catch (InterruptedException e) {e.printStackTrace();}LockSupport.park(); //消耗掉permitLockSupport.park(); //此时permit为0,中断状态为false,必然会阻塞}
}
上面程序执行后,抛出异常,程序不会运行结束。通过Dump Threads后,可以发现main处于WAITING (parking)
状态,即阻塞状态。
总结
park
调用后一定会消耗掉permit
,无论unpark
操作先做还是后做。- 如果
中断状态
为true,那么park
无法阻塞。 unpark
会使得permit
为1,并唤醒处于阻塞的线程。interrupt()
会使得中断状态
为true,并调用unpark
。sleep() / wait() / join()
调用后一定会消耗掉中断状态
,无论interrupt()
操作先做还是后做。
关于这一点,“如果中断状态
为true,那么park
无法阻塞”。在AQS源码里的acquireQueued
里,由于acquireQueued
是阻塞式的抢锁,线程可能重复着 阻塞->被唤醒 的过程,所以在这个过程中,如果遇到了中断,一定要用Thread.interrupted()
将中断状态
消耗掉,并将这个中断状态
暂时保存到一个局部变量中去。不然只要遇到中断一次后,线程在抢锁失败后却无法阻塞了。
interrupt()中断对LockSupport.park()的影响相关推荐
- LockSupport 的 park 和 unpark 以及线程中断对 park 的影响
park() Thread t1 = new Thread(() -> {System.out.println("t1 park");LockSupport.park(); ...
- LockSupport park和unpark
前言 在上一篇文章线程池返回值Future中,源码分析线程池结果获取阻塞的原因. LockSupport.unpark(t); LockSupport.parkNanos(this, nanos);或 ...
- Java中的线程休眠大法系列(三)LockSupport.park()
文章目录 前言 一.看看JDK的代码注释 二.案例 1. 查看线程状态 2.线程被打断,不抛异常 2.是否会释放锁 3.传递自定义数据 总结 前言 Java的线程休眠我们从Thread.sleep到O ...
- Thread.sleep() / Object.wait() / Condition.await() / LockSupport.park() / LockSupport.unpark() 区别
转自:https://www.cnblogs.com/tong-yuan/p/11768904.html Thread.sleep()和Object.wait()的区别 首先,我们先来看看Thread ...
- thread.sleep会释放锁吗_面试 LockSupport.park()会释放锁资源吗?
(手机横屏看源码更方便) 引子 大家知道,我最近在招人,今天遇到个同学,他的源码看过一些,然后我就开始了AQS连环问. 我:说说AQS的大致流程? 他:AQS包含一个状态变量,一个同步队列--bala ...
- 让面试官心服口服:Thread.sleep、synchronized、LockSupport.park的线程阻塞有何区别?
前言 在日常编码的过程中,我们经常会使用Thread.sleep.LockSupport.park()主动阻塞线程,或者使用synchronized和Object.wait来阻塞线程保证并发安全.此时 ...
- Android Thread interrupt 中断JAVA线程(转)
转载自:http://hi.baidu.com/%E3%C6%CE%C4%B7%E5/blog/item/d8959f1b6716c8168618bfbb.html 假如我们有一个任务如下,交给一个J ...
- 用interrupt()中断Java线程
http://hapinwater.iteye.com/blog/310558 最近在学习Java线程相关的东西,和大家分享一下,有错误之处欢迎大家指正. 假如我们有一个任务如下,交给一个Java线程 ...
- 小米集团王嵋因错误表达致歉并请辞;亚马逊云服务出现中断,许多网站受到影响;deepin 深度系统更新发布|极客头条...
整理 | 郑丽媛 头图 | CSDN 下载自东方 IC 快来收听极客头条音频版吧,智能播报由出门问问「魔音工坊」提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「 ...
最新文章
- SharePoint 2007 SDK 有了1.1版本
- application.xml定时
- Java中获取近七天的日期(包含今天)
- C#和Java的代码转换工具(开源)CSharpJavaMerger Framework
- Java学习 第四章 java面向对象(二)
- jQuery 筛选
- python——作用域 == is
- ipad怎么连接电脑_苹果连接电脑没反应怎么办
- Linux常用基本命令:三剑客命令之-awk内置函数用法
- C#一个完整的电子邮件操作类
- 实力封装:Unity打包AssetBundle(三)
- 蓝蓝设计 使用全屏照片的网页设计欣赏
- 基于机器学习的笑脸检测
- RNNoise超详细解析
- 50 Android hacks(hack 1)
- CookieSession
- 阿里架构师:双十一「大促」,多亏了 Node.js
- android rom签名 作用,Ubuntu下折腾Android笔记(一)——ROM 签名 | 翅膀~
- 爱盈利app推广专家相关介绍
- Functionlan通过星际文件系统免费使用云应用程序