该如何正确的中断一个线程的执行?
摘要:本文以一个案例的形式,来为大家详细介绍下为何中断执行的线程不起作用。
本文分享自华为云社区《【高并发】我们该如何正确的中断一个线程的执行??》,作者: 冰 河 。
写在前面
当我们在调用Java对象的wait()方法或者线程的sleep()方法时,需要捕获并处理InterruptedException异常。如果我们对InterruptedException异常处理不当,则会发生我们意想不到的后果!今天,我们就以一个案例的形式,来为大家详细介绍下为何中断执行的线程不起作用。
程序案例
例如,下面的程序代码,InterruptedTask类实现了Runnable接口,在run()方法中,获取当前线程的句柄,并在while(true)循环中,通过isInterrupted()方法来检测当前线程是否被中断,如果当前线程被中断就退出while(true)循环,同时,在while(true)循环中,还有一行Thread.sleep(100)代码,并捕获了InterruptedException异常。整个代码如下所示。
package io.binghe.concurrent.lab08; /** * @author binghe * @version 1.0.0 * @description 线程测试中断 */ public class InterruptedTask implements Runnable{ @Override public void run() { Thread currentThread = Thread.currentThread(); while (true){ if(currentThread.isInterrupted()){ break; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
上述代码的本意是通过isInterrupted()方法检查线程是否被中断了,如果中断了就退出while循环。其他线程通过调用执行线程的interrupt()方法来中断执行线程,此时会设置执行线程的中断标志位,从而使currentThread.isInterrupted()返回true,这样就能够退出while循环。
这看上去没啥问题啊!但真的是这样吗?我们创建一个InterruptedTest类用于测试,代码如下所示。
package io.binghe.concurrent.lab08; /** * @author binghe * @version 1.0.0 * @description 测试线程中断 */ public class InterruptedTest { public static void main(String[] args){ InterruptedTask interruptedTask = new InterruptedTask(); Thread interruptedThread = new Thread(interruptedTask); interruptedThread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } interruptedThread.interrupt(); } }
我们运行main方法,如下所示。
这竟然跟我们想象的不一样!不一样!不一样!这是为什么呢?
问题分析
上述代码明明调用了线程的interrupt()方法来中断线程,但是却并没有起到啥作用。原因是线程的run()方法在执行的时候,大部分时间都是阻塞在sleep(100)上,当其他线程通过调用执行线程的interrupt()方法来中断执行线程时,大概率的会触发InterruptedException异常,在触发InterruptedException异常的同时,JVM会同时把线程的中断标志位清除,所以,这个时候在run()方法中判断的currentThread.isInterrupted()会返回false,也就不会退出当前while循环了。
既然问题分析清除了,那如何中断线程并退出程序呢?
问题解决
正确的处理方式应该是在InterruptedTask类中的run()方法中的while(true)循环中捕获异常之后重新设置中断标志位,所以,正确的InterruptedTask类的代码如下所示。
package io.binghe.concurrent.lab08; /** * @author binghe * @version 1.0.0 * @description 中断线程测试 */ public class InterruptedTask implements Runnable{ @Override public void run() { Thread currentThread = Thread.currentThread(); while (true){ if(currentThread.isInterrupted()){ break; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); currentThread.interrupt(); } } } }
可以看到,我们在捕获InterruptedException异常的catch代码块中新增了一行代码。
currentThread.interrupt();
这就使得我们捕获到InterruptedException异常后,能够重新设置线程的中断标志位,从而中断当前执行的线程。
我们再次运行InterruptedTest类的main方法,如下所示。
总结
处理InterruptedException异常时要小心,如果在调用执行线程的interrupt()方法中断执行线程时,抛出了InterruptedException异常,则在触发InterruptedException异常的同时,JVM会同时把执行线程的中断标志位清除,此时调用执行线程的isInterrupted()方法时,会返回false。此时,正确的处理方式是在执行线程的run()方法中捕获到InterruptedException异常,并重新设置中断标志位(也就是在捕获InterruptedException异常的catch代码块中,重新调用当前线程的interrupt()方法)。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
AI开发实践丨客流分析之未佩戴口罩识别
摘要:通过本教程,我们可以学习客流统计应用的扩展——过线客流统计+口罩佩戴识别,可用于商超、写字楼入口安检。 本文分享自华为云社区《客流分析之未佩戴口罩识别》,作者: HiLens_feige 。 疫情虽然过去了,口罩佩戴防护依然十分重要,本文在基于头肩部检测的过线客流统计博文基础上增加口罩佩戴检测功能:采用头肩部检测人形并进行跟踪,当头肩部中心点跨过事先划定的线段时,增加客流计数,同时检查此人是否佩戴口罩;过线前后的人形将使用不同颜色的框表示,画面中会实时显示客流数量,若有未佩戴口罩的人也会产生告警。 准备工作 本文将使用华为云ModelArts进行人形检测模型的训练,并使用ModelBox框架进行应用开发,使用前开发者需要完成如下准备工作: 参考此教程完成设备的注册; 参考此教程完成ModelBoxSDK的安装。 技能开发 这个应用对应的ModelBox版本已经做成模板放在华为云OBS中,可以用sdk中的solution.bat工具下载,接下来我们给出该应用在ModelBox中的完整开发过程: 1)下载模板 执行.\solution.bat -l可看到当前公开的技能模板: PS █...
- 下一篇
详细剖析|袋鼠云数栈前端框架Antd 3.x 升级 4.x 的踩坑之路
袋鼠云数栈从2016年发布第⼀个版本开始,就始终坚持着以技术为核⼼、安全为底线、提效为⽬标、中台为战略的思想,坚定不移地⾛国产化信创路线,不断推进产品功能迭代、技术创新、服务细化和性能升级。 在数栈过去的产品迭代中受限于当前组件的版本,积累了很多待解决的问题,随着新的功能需求不断增加,很多原先的组件以及交互设计需要进行优化。 2月,伴随着数栈 UI5.0 的焕新升级,数栈前端团队一起将组件框架 antd 从 v3.x 升级到了 v4.x,更新组件的 UI,提升产品的交互体验,使数栈产品能够更加灵活地适应未来产品功能迭代的需求。 本文将总结归纳袋鼠云数栈前端框架Antd 从3.x 升级到4.x 的相关步骤,及在这个过程中踩过的坑,解决的问题。 兼容性问题 第三方依赖兼容问题 · React - 最低 v16.9,部分组件使用 hooks 重构 ( react 升级相关文档:https://sourl.cn/6bM4Ep) · Less - 最低 v3.1.0,建议升级到 less 4.x; · @ant-design/icons-antd - 不再内置 Icon 组件,请使用独立的包。 ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Linux系统CentOS6、CentOS7手动修改IP地址
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Windows10,CentOS7,CentOS8安装Nodejs环境