前言:在Java多线程中,中断一直围绕着我们,当我们阅读各种关于Java多线程的资料、书籍时,“中断”一词总是会出现,笔者对其的理解也是朦朦胧胧,因此非常有必要搞清楚Java多线程的中断机制。

1.Java中断机制是什么

Java 中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。这好比老师要求学生要高质量完成作业,但是学生是否高质量完成作业,完全取决于学生自己。

Java 中断模型非常的简单:每个线程对象里都有一个 boolean 类型的标识(当然jdk源码中是看不到该标识位,它位于虚拟机层面),代表着是否有中断请求(该请求可以来自所有线程,包括被中断的线程本身)。例如,当线程 t1 想中断线程 t2,只需要在线程 t1 中将线程 t2 对象的中断标识置为 true,然后线程 t2 可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

综合上述两段文字的描述,对Java中断机制进行总结:Java中断是一种机制,并不是真的停止线程,而是对线程对象打上一个中断标记,具体如何处理还是要看被中断线程如何操作。

2.Thread类提供的中断相关方法

中断线程,注意该方法未被static修饰,因此该方法被Thread对象调用。并且该方法仅仅是为线程打一个中断的标记,将线程中断状态设置为true。

测试Thread对象是否中断,主要该方法也未被static修饰,因此该方法也应该被Thread对象调用,如果线程被打了中断标记,返回true,否则返回false。特别注意该方法不影响中断状态,这里主要和interrupted()方法做对比。

测试当前线程是否中断,注意该方法被static修饰,并且该方法会清除线程的中断标记,将中断标记设置为false。也就是说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

总结:

#1.真正中断线程的方法为interrupt(),并且该方法也仅仅是为Thread对象打一个中断的标记,而不是立即终止线程。

#2.isInterrupted()方法未被static修饰,测试Thread对象是否中断,也就是判断线程对象是否有中断标记。该方法不会清除中断标记

#3.interrupted()方法被static修饰,测试当前线程是否中断,注意该方法会清除线程中断的标记

以上三个函数的源码逻辑简单,主要调用了native方法,这里不进行阐述。

3.中断处理时机

中断作为一种协作机制,不会强求被中断线程一定要在某个点进行处理。实际上,被中断线程只需在合适的时候处理即可,如果没有合适的时间点,甚至可以不处理,这时候在任务处理层面,就跟没有调用中断方法一样。“合适的时候”与线程正在处理的业务逻辑紧密相关。

处理时机决定着程序的效率与中断响应的灵敏性,频繁的检查中断状态可能会使程序执行效率下降,相反,检查的较少可能使中断请求得不到及时响应。如果发出中断请求之后,被中断的线程继续执行一段时间不会给系统带来灾难,那么就可以将中断处理放到方便检查中断,同时又能从一定程度上保证响应灵敏度的地方。当程序的性能指标比较关键时,可能需要建立一个测试模型来分析最佳的中断检测点,以平衡性能响应灵敏性

4.线程中断举例

  • 停不下来的线程
 public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
System.out.println("我是t1线程");
});
t1.start();
Thread.sleep(200);
t1.interrupt();
}

上述代码运行结果如下:

从运行结果来看,线程并未终止成功,这也符合interrupt()函数的功能描述,仅仅是为线程打一个中断标记,具体怎么处理还要看线程自己如何操作。

将上面代码做如下修改:

 public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
if (Thread.currentThread().isInterrupted()) { // 对中断做处理
System.out.println("t1线程被中断了");
return;
}
System.out.println("i=" + (i + 1));
}
System.out.println("我是t1线程");
});
t1.start();
Thread.sleep(200);
t1.interrupt();
}

其运行结果如下:

上述代码对中断进行了处理,所以循环并未走完,t1线程被成功中断。

  • interrupted()和isInterrupted()的区别
 public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
System.out.println("我是t1线程");
});
t1.start();
Thread.sleep(200);
t1.interrupt();
System.out.println("isInterrupted()=" + t1.isInterrupted());
System.out.println("isInterrupted()=" + t1.isInterrupted());
System.out.println("interrupted()=" + t1.interrupted());
System.out.println("interrupted()=" + Thread.interrupted());
}

运行结果如下:

为什么会出现上面的运行结果呢,从源码上最容易理解:

  • 该方法未被static修饰【isInterrupted(false)表示不会清除中断标志,isInterrupted为native方法】,所以该方法被Thread对象调用,返回Thread对象的中断状态。
  • 该方法被static修饰【注意isInterrupted(true)表示会清除中断标志】,该方法返回当前线程的中断状态,在上述代码中,当前线程为main方法代表的主线程,并没有进行中断操作,所以打印结果为false。

修改上述代码:

 public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
System.out.println("我是t1线程");
});
t1.start();
Thread.sleep(200);
t1.interrupt();
Thread.currentThread().interrupt();
System.out.println("isInterrupted()=" + t1.isInterrupted());
System.out.println("isInterrupted()=" + t1.isInterrupted());
System.out.println("interrupted()=" + t1.interrupted());
System.out.println("interrupted()=" + Thread.interrupted());
}

注意第11行代码,其运行结果如下:

从结果充分说明连续两次调用interrupted()会清除中断标记。

总结

通过上述的分析,对Java的中断机制的核心要点做如下总结:

  • Java中断机制是一种协作机制,中断只是给线程打一个中断标记,具体如何操作还要看线程自己,by myself。
  • interrupt()函数作用仅仅是为线程打一个中断标记
  • interrupted()与isInterrupted()函数,都是返回线程的中断状态,但是interrupted()被static修饰,返回当前线程的中断状态,并且会清除线程的中断标记;而isInterrupted()未被static修饰,被Thread对象调用,它不会清除线程的中断标记

by Shawn Chen,2019.02.17,上午。

Java多线程——中断机制的更多相关文章

  1. Java多线程9:中断机制

    一.概述 之前讲解Thread类中方法的时候,interrupt().interrupted().isInterrupted()三个方法没有讲得很清楚,只是提了一下.现在把这三个方法同一放到这里来讲, ...

  2. JAVA多线程之中断机制(stop()、interrupted()、isInterrupted())

    一,介绍 本文记录JAVA多线程中的中断机制的一些知识点.主要是stop方法.interrupted()与isInterrupted()方法的区别,并从源代码的实现上进行简单分析. JAVA中有3种方 ...

  3. java 多线程5: java 终止线程及中断机制 (stop()、interrupt() 、interrupted()、isInterrupted())

    JAVA中有3种方式可以终止正在运行的线程 ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()方法强行终止线程.但stop()方法已经过期了,不推荐使用 ③使用中断机制i ...

  4. java 多线程6: 中断机制 优雅的终止java线程

    前文 java 多线程5: java 终止线程及中断机制 (stop().interrupt() .interrupted().isInterrupted()) 使用 interrupt() 和 in ...

  5. JAVA多线程之中断机制(如何处理中断?)

    一,介绍 这篇文章主要记录使用 interrupt() 方法中断线程,以及如何对InterruptedException进行处理.感觉对InterruptedException异常进行处理是一件谨慎且 ...

  6. Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock

    在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...

  7. 50个Java多线程面试题

    不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者 ...

  8. 50个Java多线程面试题(上)

    Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者精通多线程技术并且有丰富的 Java 程序开发.调试.优化经验 ...

  9. Java多线程与并发面试题

    1,什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成一 ...

随机推荐

  1. C# - 2017微软校园招聘笔试题 之 MS Recognition[待解决]

    MS Recognition 在线提交: hihoCoder 1402 http://hihocoder.com/problemset/problem/1402 类似: OpenJudge - I:P ...

  2. 【ASP.NET Core快速入门】(十)Cookie-based认证实现

    准备工作 新建MVC项目,然后用VSCode打开 dotnet new mvc --name MvcCookieAuthSample 在Controllers文件夹下新建AdminController ...

  3. 【深度学习与TensorFlow 2.0】卷积神经网络(CNN)

    注:在很长一段时间,MNIST数据集都是机器学习界很多分类算法的benchmark.初学深度学习,在这个数据集上训练一个有效的卷积神经网络就相当于学习编程的时候打印出一行“Hello World!”. ...

  4. web前端安全

    之前对web前端安全进行了总结,想给大家分享一下,有不对的地方,大家多多交流,由于写在了PPT上,只好给大家一张一张粘上来,希望大家不要在意,了解知识为主

  5. JDK源码分析(7)之 Reference 框架概览

    对于Reference类大家可能会比较陌生,平时用的也比较少,对他的印象可能仅停在面试的时候查看引用相关的知识点:但在仔细查看源码后发现Reference还是非常实用的,平时我们使用的类都是强引用的, ...

  6. 消息队列中间件(三)Kafka 入门指南

    Kafka 来源 Kafka的前身是由LinkedIn开源的一款产品,2011年初开始开源,加入了 Apache 基金会,2012年从 Apache Incubator 毕业变成了 Apache 顶级 ...

  7. [ASP.NET] 如何利用Javascript分割檔案上傳至後端合併

    最近研究了一下如何利用javascript進行檔案分割上傳並且透過後端.特地記錄一下相關的用法 先寫限制跟本篇的一些陷阱 1.就是瀏覽器的支援了 因為本篇有用到blob跟webworker 在ie中需 ...

  8. WPF 窗口大小自适应

    在设置桌面不同分辨率以及较大DPI下,窗口如何显示的问题. 方案一 设置窗口最大值和最小值显示 通过对比当前屏幕的可显示区域,将窗口高宽最大值和最小值,设置为窗口的实际高宽(此例中仅设置高度) 界面设 ...

  9. C# 处理PPT水印(一)——添加水印效果(文字水印、图片水印)

    对文档添加水印可以有效声明和保护文档,是保护重要文件的方式之一.在PPT文档中同样也可以设置水印,包括文本水印和图片水印,本文将讲述如何通过Spire.Presentation for .NET来对P ...

  10. Qt Creator的下载和安装

    原文:https://blog.csdn.net/weixin_38090427/article/details/83827678 一,Qt和Qt Creator的区别 Qt是C++的一个库,或者说是 ...