使用 interrupt() 和 interrupted() 判断来终止线程


  1. public class Run {
  2. public static void main(String[] args) {
  3. try {
  4. MyThread thread = new MyThread();
  5. thread.start();
  6. Thread.sleep(2000);
  7. thread.interrupt();//请求中断MyThread线程
  8. } catch (InterruptedException e) {
  9. System.out.println("main catch");
  10. e.printStackTrace();
  11. }
  12. System.out.println("end!");
  13. }
  14. }

main线程睡眠2000ms后,执行第8行中断MyThread线程。

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. for (int i = 0; i < 500000; i++) {
  6. if (this.interrupted()) {
  7. System.out.println("should be stopped and exit");
  8. break;
  9. }
  10. System.out.println("i=" + (i + 1));
  11. }
  12. System.out.println("this line is also executed. thread does not stopped");//尽管线程被中断,但并没有结束运行。这行代码还是会被执行
  13. }
  14. }

当MyThread获得CPU执行时,第6行的 if 测试中,检测到中断标识被设置。即MyThread线程检测到了main线程想要中断它的 请求。

大多数情况下,MyThread检测到了中断请求,对该中断的响应是:退出执行(或者说是结束执行)。

但是,上面第5至8行for循环,是执行break语句跳出for循环。但是,线程并没有结束,它只是跳出了for循环而已,它还会继续执行第12行的代码....

因此,我们的问题是,当收到了中断请求后,如何结束该线程呢?

一种可行的方法是使用 return 语句 而不是 break语句。。。。。哈哈。。。

不过使用return 没有抛异常那么好,不能将事件传播

优雅的解决

抛异常方法 抛出InterruptedException异常

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. try{
  6. for (int i = 0; i < 500000; i++) {
  7. if (this.interrupted()) {
  8. System.out.println("should be stopped and exit");
  9. throw new InterruptedException();
  10. }
  11. System.out.println("i=" + (i + 1));
  12. }
  13. System.out.println("this line cannot be executed. cause thread throws exception");//这行语句不会被执行!!!
  14. }catch(InterruptedException e){
  15. System.out.println("catch interrupted exception");
  16. e.printStackTrace();
  17. }
  18. }
  19. }

当MyThread线程检测到中断标识为true后,在第9行抛出InterruptedException异常。这样,该线程就不能再执行其他的正常语句了(如,第13行语句不会执行)。


因此,上面就是一个采用抛出异常的方式来结束线程的示例。尽管该示例的实用性不大。原因是我们 生吞了中断。

在第14行,我们直接catch了异常,然后打印输出了一下而已,调用栈中的更高层的代码是无法获得关于该异常的信息的。

第16行的e.printStackTrace()作用就相当于

在这里是生吞了异常  由于
this.interrupted()在第一次调用后清楚中断状态为false(注意这里是调用

this.interrupted()这个方法会清楚中断状态,而不是抛出异常会清除中断状态,而isInterrupted()这个不会清除中断状态,这两种区别在

1.仅仅记录 InterruptedException 也不是明智的做法,因为等到人来读取日志的时候,再来对它作出处理就为时已晚了。

有时候抛出 InterruptedException 并不合适,例如当由 Runnable 定义的任务调用一个可中断的方法时,就是如此。在这种情况下,不能重新抛出 InterruptedException,但是您也不想什么都不做。当一个阻塞方法检测到中断并抛出 InterruptedException 时,它清除中断状态。如果捕捉到 InterruptedException 但是不能重新抛出它,那么应该保留中断发生的证据,以便调用栈中更高层的代码能知道中断,并对中断作出响应。该任务可以通过调用 interrupt() 以 “重新中断” 当前线程来完成
2.因为,run方法是实现的Runnable接口中的方法。不能像下面这样定义,也即上面所说的:“不能重新抛出InterruptedException”。
        @Override
public void run() throws InterruptedException{//这是错误的
//do something...

代码改良

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. try{
  6. for (int i = 0; i < 500000; i++) {
  7. if (this.interrupted()) {
  8. System.out.println("should be stopped and exit");
  9. throw new InterruptedException();
  10. }
  11. System.out.println("i=" + (i + 1));
  12. }
  13. System.out.println("this line cannot be executed. cause thread throws exception");
  14. }catch(InterruptedException e){
  15. /**这样处理不好
  16. * System.out.println("catch interrupted exception");
  17. * e.printStackTrace();
  18. */
  19. Thread.currentThread().interrupt();//这样处理比较好
  20. }
  21. }
  22. }

这样,就由 生吞异常 变成了 将 异常事件 进一步扩散了。 保留了中断的证据

ps 
对于可取消的阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号interrupt()后, 会抛出InterruptedException。就不需要手动抛异常法了,只需要在捕获异常块再次标记中断即可



java 多线程6: 中断机制 优雅的终止java线程的更多相关文章

  1. Java 多线程基础(十)interrupt()和线程终止方式

    Java 多线程基础(十)interrupt()和线程终止方式 一.interrupt() 介绍 interrupt() 定义在 Thread 类中,作用是中断本线程. 本线程中断自己是被允许的:其它 ...

  2. Java多线程干货系列—(一)Java多线程基础

    前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的 ...

  3. [转]Java多线程干货系列—(一)Java多线程基础

    Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...

  4. Java多线程编程核心技术-第1章-Java多线程技能-读书笔记

    第 1 章 Java 多线程技能 本章主要内容 线程的启动 如何使线程暂停 如何使线程停止 线程的优先级 线程安全相关的问题 1.1 进程和多线程的概念及线程的优点 进程是操作系统结构的基础:是一次程 ...

  5. “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

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

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

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

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

  9. Java多线程总结(二)锁、线程池

    掌握Java中的多线程,必须掌握Java中的各种锁,以及了解Java中线程池的运用.关于Java多线程基础总结可以参考我的这篇博文Java多线程总结(一)多线程基础 转载请注明出处——http://w ...

随机推荐

  1. exception PLS-00103: Encountered the symbol "(" when expecting one of the following:

      exception PLS-00103: Encountered the symbol "(" when expecting one of the following: Cre ...

  2. java中list、set和map 的区别(转)

    作者:佚名出处:IT专家网论坛 2009-06-17 13:00   List按对象进入的顺序保存对象,不做排序或编辑操作.Set对每个对象只接受一次,并使用自己内部的排序方法(通常,你只关心某个元素 ...

  3. Log4net的配置-按照日期+文件大小混合分割

    ender name="DebugAppender" type="log4net.Appender.RollingFileAppender"><fi ...

  4. Linux下通用线程池的创建与使用

    线程池:简单地说,线程池 就是预先创建好一批线程,方便.快速地处理收到的业务.比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高. 在linux中,使用的 ...

  5. 【J2EE之web应用】java集群概念

    在学习web应用进行部署的时候,遇到一个名词java集群,(事实上遇到非常多名词╭(╯^╰)╮~~~).不懂意思就查一查! 在这里做个笔记! 没有什么高深见解,就搞明确几个概念,java集群的特点 . ...

  6. 【laravel5.4】迁移文件的生成、修改、删除

    建议直接去官方文档查看: https://laravel-china.org/docs/laravel/5.4/migrations#creating-columns 1.生成迁移: 主要方式:1.创 ...

  7. 自己总结的javascript基础知识

    为了面试自己写的概要,参考文献:<javascript高级程序设计> 1.选择符API *querySelector() querySelector()接收一个css选择符,返回与选择符匹 ...

  8. PHP-Open Flash Chart报表生成

    下载: http://www.cnblogs.com/huangcong/archive/2013/01/27/2878650.html 安装: 解压ZIP包, 将open-flash-chart.s ...

  9. std::copy 和 std::back_inserter

    #define print_vector(v1) \ for(auto iter = v1.begin();iter != v1.end();iter++) \ cout<<*iter&l ...

  10. HDUOJ---1133(卡特兰数扩展)Buy the Ticket

    Buy the Ticket Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...