首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。

所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。
而 Thread.interrupt 的作用其实也不是中断线程,而是「通知线程应该中断了」,
具体到底中断还是继续运行,应该由被通知的线程自己处理。

具体来说,当对一个线程,调用 interrupt() 时,
① 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。仅此而已。
② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。

interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。
也就是说,一个线程如果有被中断的需求,那么就可以这样做。
① 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。
② 在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)


interrupt()方法:对目标线程发送中断请求,看其源码会发现最终是调用了一个本地方法实现的线程中断;

interrupted()方法:返回目标线程是否中断的布尔值(通过本地方法实现),且返回后会重置中断状态为未中断=false;

isInterrupted()方法:该方法返回的是线程中断与否的布尔值(通过本地方法实现),不会重置中断状态;


示例1(中断失败)

/**
* 微信公众号:Java技术栈
*/
private static void test1() {
Thread thread = new Thread(() -> {
while (true) {
Thread.yield();
}
});
thread.start();
thread.interrupt();
}

请问示例1中的线程会被中断吗?答案:不会,因为虽然给线程发出了中断信号,但程序中并没有响应中断信号的逻辑,所以程序不会有任何反应继续原样执行。跟没有中断是一样的。

示例2:(中断成功)

/**
* 微信公众号:Java技术栈
*/
private static void test2() {
Thread thread = new Thread(() -> {
while (true) {
Thread.yield(); // 响应中断
if (Thread.currentThread().isInterrupted()) {
System.out.println("Java技术栈线程被中断,程序退出。");
return;
}
}
});
thread.start();
thread.interrupt();
}

我们给示例2加上了响应中断的逻辑,程序接收到中断信号打印出信息后返回退出。return退出。

示例3(中断失败)

/**
* 微信公众号:Java技术栈
*/
private static void test3() throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
// 响应中断
if (Thread.currentThread().isInterrupted()) {
System.out.println("Java技术栈线程被中断,程序退出。");
return;
} try {
Thread.sleep();
} catch (InterruptedException e) {
System.out.println("Java技术栈线程休眠被中断,程序退出。");
}
}
});
thread.start();
Thread.sleep();
thread.interrupt();
}

可以看出 sleep() 方法被中断后会清除中断标记,所以循环会继续运行。

示例4(中断成功)

/**
* 微信公众号:Java技术栈
*/
private static void test4() throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
// 响应中断
if (Thread.currentThread().isInterrupted()) {
System.out.println("Java技术栈线程被中断,程序退出。");
return;
} try {
Thread.sleep();
} catch (InterruptedException e) {
System.out.println("Java技术栈线程休眠被中断,程序退出。");
Thread.currentThread().interrupt();
}
}
});
thread.start();
Thread.sleep();
thread.interrupt();
}

示例4全部信息输出并正常退出,只是在 sleep() 方法被中断并清除标记后手动重新中断当前线程,然后程序接收中断信号返回退出。


我们的系统肯定有些线程为了保证业务需要是要常驻后台的,一般它们不会自己终止,需要我们通过手动来终止它们。我们知道启动一个线程是start方法,自然有一个对应的终止线程的stop方法,通过stop方法可以很快速、方便地终止一个线程。

通过注解@Deprecated看出stop方法被标为废弃的方法,jdk在以后的版本中可能被移除,不建议大家使用这种API。

那为什么这么好的一个方法怎么不推荐使用,还要标注为废弃呢?

假设有这样的一个业务场景,一个线程正在处理一个复杂的业务流程,突然间线程被调用stop而意外终止,这个业务数据还有可能是一致的吗?这样是肯定会出问题的,stop会释放锁并强制终止线程,造成执行一半的线程终止,带来的后果也是可想而知的,这就是为什么jdk不推荐使用stop终止线程的方法的原因,因为它很暴力会带来数据不一致性的问题。

正因为stop方法太过暴力,所以一般不推荐使用,除非你非常清楚你自己的业务场景,用stop终止不会给你的业务带来影响。

说了这么多,那如何优雅地终止一个线程呢?看看下面的程序。

其实也不难,只需要添加一个变量,判断这个变量在某个值的时候就退出循环,这时候每个循环为一个整合不被强行终止就不会影响单个业务的执行结果。

hread.interrupt()到底意味着什么的更多相关文章

  1. Java并发专题(一)认识线程

    1.1 认识线程 线程是轻量级进程,也是程序执行的一个路径,每一个线程都有自己的局部变量表.程序计数器(指向正在执行的指令指针)以及各自的生命周期,现代操作系统中一般不止一个线程在运行.比如说,当我们 ...

  2. java并发编程(五)----(JUC)ReentrantLock

    上一节我们了解了Lock接口的一些简单的说明,知道Lock锁的常用形式,那么这节我们正式开始进入JUC锁(java.util.concurrent包下的锁,简称JUC锁).下面我们来看一下Lock最常 ...

  3. 关于InterruptedException的两篇博文的转载

    博文一:https://www.jianshu.com/p/a8abe097d4ed InterruptedException异常 在了解InterruptedException异常之前应该了解以下的 ...

  4. HackerNews——《Pokemon Go玩家存在巨大的安全风险》

    译者注:原文来自HackerNews,首发tumblr,标题为Pokemon Go is a huge security risk.作者Adam Reeve,附一张这个胖子的帅照   (正文)之所以会 ...

  5. 如何设计一门语言(七)——闭包、lambda和interface

    人们都很喜欢讨论闭包这个概念.其实这个概念对于写代码来讲一点用都没有,写代码只需要掌握好lambda表达式和class+interface的语义就行了.基本上只有在写编译器和虚拟机的时候才需要管什么是 ...

  6. 【转】漫谈iOS程序的证书和签名机制

    转自:漫谈iOS程序的证书和签名机制 接触iOS开发半年,曾经也被这个主题坑的摸不着头脑,也在淘宝上买过企业证书签名这些服务,有大神都做了一个全自动的发布打包(不过此大神现在不卖企业证书了),甚是羡慕 ...

  7. Java线程并发:知识点

    Java线程并发:知识点   发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用.   逃逸:在对象尚未准备 ...

  8. 漫谈iOS程序的证书和签名机制

    接触iOS开发半年,曾经也被这个主题坑的摸不着头脑,也在淘宝上买过企业证书签名这些服务,有大神都做了一个全自动的发布打包(不过此大神现在不卖企业证书了),甚是羡慕和崇拜.于是,花了一点时间去研究了一下 ...

  9. Guava学习笔记(1):Optional优雅的使用null

    转自:http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html 参考:[Google Guava] 1.1-使用和避免nu ...

随机推荐

  1. mvc视图双下拉框联动

    html部分的代码 <tr class="trs"> <td class="item1"><div class="ite ...

  2. ORA-03113: 通信通道的文件结束解决方法一例

    开发项目时,使用的是Oracle数据库.最近遇到了“ORA-03113: 通信通道的文件结束”错误.如下图所示: 经过网上查资料和请教同事,终于找到了解决ORA-03113错误的办法. 解决步骤如下: ...

  3. 隐马尔科夫模型(Hidden Markov Models) 系列之三

    转自:http://blog.csdn.net/eaglex/article/details/6418219 隐马尔科夫模型(Hidden Markov Models) 定义 隐马尔科夫模型可以用一个 ...

  4. HubSpot company数据在UI上的展示和通过API方式进行获取

    在网页查看所有的company: https://app.hubspot.com/contacts/6798828/companies/list/view/all/? 打开第一个名为SAP的compa ...

  5. Spark调用Linux命令实现解压和压缩功能

    一.应用场景 在Spark程序中调用Linux命令,实现一些程序难以实现的功能,例如:发送模拟邮件.文件打包或解压等等 二.代码实现 package big.data.analyse.linux im ...

  6. 2. 代理模式(C++)

    1.介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问.这样实现了业务和核心功能分离. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口.在某些情况下,一个对象不适合或者不能 ...

  7. xampp1.8.3 配置 php5.x 访问 SQL Server 2008

    1.安装xampp 2.下载php sqlsrv扩展 Microsoft Drivers 3.2 for PHP for SQL Server 官方下载地址: http://www.microsoft ...

  8. luoguP5495:Dirichlet 前缀和

    题意:给定数组a[]的生成方式,然后b[i]=∑a[j]  ,(i%j==0),求所有b[i]的异或和.所有运算%2^32; 思路:高维前缀和的思想,先筛出所有素数,然后把每个素数当成一维,那么分开考 ...

  9. Java 构造方法、final

    构造方法:构造(创建)对象时使用的方法. 方法名必须与类名称完全相匹配: 构造方法不需要返回类型: 构造方法不能被static.final等关键字修饰,且不能有return返回语句: 伴随着new被调 ...

  10. python基础之四:list、tuple

    一.列表 list # 列表 ''' 类似str,可以进行切片 ''' li = [', [1, 2, 3], 55, 'we all in ', 'Tom', ''] print(li[0:2]) ...