博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何理解 Java 的线程中断机制?
阅读量:4072 次
发布时间:2019-05-25

本文共 3711 字,大约阅读时间需要 12 分钟。

前言

本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见

正文

在Java中,线程中断是一种重要的线程协作机制。从表面上理解,中断就是让目标线程停止执行的意思,实际上并非完全如此。

在专栏前面我们提到了 stop() 方法停止线程的坏处,详情请见——

在 JDK 中是否有提供完善的支持线程退出的能力呢?答案是肯定的,那就是线程中断。

严格地讲,线程中断并不会使线程立即退出,而是给线程发送一个通知,告知目标线程,有人希望你退出啦!

至于目标线程接到通知后如何处理,则完全由目标线程自行决定这点很重要,如果中断后,线程立即无条件退出,我们就又会遇到 stop 方法的老问题。

有三个方法与线程中断有关,这三个方法看起来很像,可能会引起混淆和误用,希望大家注意。

这三个方法都来自于 java.lang.Thread

public void interrupt(); //中断线程public boolean isInterrupted(); //判断当前线程是否已经被中断public static boolean interrupted(); //判断当前线程是否已经被中断,并且清除当前中断状态

Thread.interrupt() 方法是一个实例方法。 它通知目标线程中断,也就是设置中断标志位。 中断标志位表示当前线程已经被中断了。

Thread.isInterrupted() 方法也是实例方法,它判断当前线程是否被中断(通过检査中断标志位)。

最后的静态方法 Thread.interrupted() 也可用来判断当前线程的中断状态,但同时会清除当前线程的中断标志位状态。

Thread.currentThread.interrupt();

package com.shockang.study.java.concurrent.thread.interrupt;/** * sleep中断后 抛出异常被重置中断状态 * 如果希望sleep后可以判断中断状态,则必须在sleep的异常处理中,在设置中断 * * @author Administrator */public class InterruptSleepThread {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
@Override public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted!"); break; } try {
Thread.sleep(2000); // 推荐使用 TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) {
System.out.println("Interrupted When Sleep"); //设置中断状态 Thread.currentThread().interrupt(); } Thread.yield(); } } }; t1.start(); Thread.sleep(2000); t1.interrupt(); }}

在 catch 子句部分,由于已经捕获了中断,我们可以立即退出线程。

但在这里,我们并没有这么做,因为也许在这段代码中,我们还必须进行后续的处理来保证数据的一致性和完整性,

因此,执行了 Thread.interrupt 方法再次中断自己,置上中断标记位。

只有这么做,在前面的中断检査中,才能发现当前线程已经被中断了。

注意: Thread.sleep() 方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么在下一次循环开始时,就无法捕获这个中断,故在异常处理中,再次设置中断标记位。

java.lang.Thread 源码解析 (JDK8)

/** * 中断此线程。  *  * 除非当前线程正在中断自身(这是始终允许的),否则将调用此线程的checkAccess方法,这可能会导致抛出SecurityException。  *  * 如果此线程在调用对象类的 wait()、wait(long) 或wait(long, int) 方法时被阻塞, *  * 或者在调用此类的join()、join(long)、join(long, int)、sleep(long) 或sleep(long, int)方法时被阻塞, *  * 则其中断状态将被清除,并且它将接收到InterruptedException。 *  * 如果此线程在I/O操作中被阻塞在中断通道上,则通道将被关闭,线程的中断状态将被设置,并且线程将接收java.nio.channels.ClosedByInterruptException。  *  * 如果该线程在java.nio.channels.Selector中被阻塞,那么该线程的中断状态将被设置,并且它将立即从选择操作返回,可能返回一个非零值,就像调用了选择器的唤醒方法一样。  *  * 如果前面的条件都不成立,那么这个线程的中断状态将被设置。  *  * 中断一个非活动线程不需要有任何效果。  *  * @throws SecurityException–如果当前线程无法修改此线程 *  */public void interrupt() {
if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) {
Interruptible b = blocker; if (b != null) {
interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0();}
/** * 测试此线程是否已中断。 *  * 线程的中断状态不受此方法的影响。  *  * 由于线程在中断时不活动而被忽略的线程中断将由返回false的方法反映。  *  * @return 如果此线程已中断,则为true;否则为假。 */public boolean isInterrupted() {
return isInterrupted(false);}/** * 测试某个线程是否被中断。中断状态是否重置取决于传递的ClearInterrupted的值 */private native boolean isInterrupted(boolean ClearInterrupted);
/** * 测试当前线程是否已中断。 *  * 此方法清除线程的中断状态。 *  * 换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false *  * (除非当前线程在第一个调用清除其中断状态之后,第二个调用检查它之前再次中断)。 *  * 由于线程在中断时不活跃而被忽略的线程中断,将由这个方法返回false *  * @return true 当前线程成功被中断 *         false 当前线程未被中断 */public static boolean interrupted() {
return currentThread().isInterrupted(true);}

转载地址:http://wugji.baihongyu.com/

你可能感兴趣的文章
《数据库系统概论》 第二章 关系数据库
查看>>
《数据库系统概论》 第三章 关系数据库标准语言SQL
查看>>
SQL语句(二)查询语句
查看>>
SQL语句(六) 自主存取控制
查看>>
《计算机网络》第五章 运输层 ——TCP和UDP 可靠传输原理 TCP流量控制 拥塞控制 连接管理
查看>>
堆排序完整版,含注释
查看>>
二叉树深度优先遍历和广度优先遍历
查看>>
生产者消费者模型,循环队列实现
查看>>
PostgreSQL代码分析,查询优化部分,process_duplicate_ors
查看>>
PostgreSQL代码分析,查询优化部分,canonicalize_qual
查看>>
PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()
查看>>
ORACLE权限管理调研笔记
查看>>
移进规约冲突一例
查看>>
IA32时钟周期的一些内容
查看>>
SM2椭圆曲线公钥密码算法
查看>>
获得github工程中的一个文件夹的方法
查看>>
《PostgreSQL技术内幕:查询优化深度探索》养成记
查看>>
PostgreSQL查询优化器详解之逻辑优化篇
查看>>
STM32中assert_param的使用
查看>>
C语言中的 (void*)0 与 (void)0
查看>>