InterruptedException和中断线程的说明

如果没有将InterruptedException检查为异常,则可能甚至没人会注意到它-这实际上可以防止这些年来的几个错误。 但是由于必须对其进行处理,因此许多人不正确或不加考虑地处理它。 让我们以一个线程的简单示例为例,该线程定期进行一些清理,但大多数情况下在两次睡眠之间进行。

class Cleaner implements Runnable {Cleaner() {final Thread cleanerThread = new Thread(this, "Cleaner");cleanerThread.start();}@Overridepublic void run() {while(true) {cleanUp();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}private void cleanUp() {//...}}

此代码在很多层上都是错误的!

  1. 在某些环境中,在构造函数中启动Thread可能不是一个好主意,例如,某些框架(如Spring)将创建动态子类以支持方法拦截。 最后,我们将从两个实例运行两个线程。
  2. 吞下了InterruptedException ,并且异常本身未正确记录
  3. 此类为每个实例启动一个新线程,它应改用ScheduledThreadPoolExecutor ,在许多实例之间共享(更健壮和更有效地使用内存)
  4. 同样,使用ScheduledThreadPoolExecutor我们可以避免自己编写睡眠/工作循环代码,并且还可以切换到固定速率,而不是此处介绍的固定延迟行为。
  5. 最后但并非最不重要的一点是,即使Cleaner实例不再被其他任何东西引用,也没有办法摆脱该线程。

所有问题都是有效的,但是吞下InterruptedException是其最大的罪过。 在我们理解原因之前,让我们先思考一下该异常的含义以及如何利用它来优雅地中断线程。 JDK中的许多阻止操作都声明抛出InterruptedException ,包括:

  • Object.wait()
  • Thread.sleep()
  • Process.waitFor()
  • AsynchronousChannelGroup.awaitTermination()
  • java.util.concurrent.*各种阻塞方法,例如ExecutorService.awaitTermination()Future.get()BlockingQueue.take()Semaphore.acquire() Condition.await()以及许多其他方法
  • SwingUtilities.invokeAndWait()

请注意,阻塞I / O不会引发InterruptedException (这很可惜)。 如果所有这些类都声明了InterruptedException ,那么您可能想知道何时会抛出此异常?

  • 当某个线程在声明InterruptedException某些方法上被阻塞并且您在该线程上调用Thread.interrupt()时,很可能阻塞的方法将立即引发InterruptedException
  • 如果将任务提交到线程池( ExecutorService.submit() ),并且在执行任务时调用Future.cancel(true) 。 在这种情况下,线程池将尝试为您中断正在运行该任务的线程,从而有效地中断您的任务。

知道InterruptedException实际含义后,我们就能够正确地处理它。 如果有人试图中断我们的线程,而我们通过捕获InterruptedException发现了它,则最合理的做法是让该线程完成,例如:

class Cleaner implements Runnable, AutoCloseable {private final Thread cleanerThread;Cleaner() {cleanerThread = new Thread(this, "Cleaner");cleanerThread.start();}@Overridepublic void run() {try {while (true) {cleanUp();TimeUnit.SECONDS.sleep(1);}} catch (InterruptedException ignored) {log.debug("Interrupted, closing");}}//...   @Overridepublic void close() {cleanerThread.interrupt();}
}

注意, try-catch块现在围绕while循环。 这样,如果sleep()抛出InterruptedException ,我们将跳出循环。 您可能会争辩说,我们应该记录InterruptedException的堆栈跟踪。 这取决于情况,因为在这种情况下中断线程是我们真正期望的,而不是失败。 但这取决于你。 最重要的是,如果sleep()被另一个线程中断,我们将很快完全脱离run() 。 如果您非常小心,您可能会问,如果线程在cleanUp()方法中而不是在睡眠时中断线程,会发生什么情况? 通常,您会遇到这样的手动标记:

private volatile boolean stop = false;@Override
public void run() {while (!stop) {cleanUp();TimeUnit.SECONDS.sleep(1);}
}@Override
public void close() {stop = true;
}

但是请注意, stop标志(必须是volatile !)不会中断阻塞操作,我们必须等到sleep()完成。 另一方面,有人可能会争辩说,显式flag可以更好地控制我们,因为我们可以随时监视其值。 事实证明,线程中断的工作方式相同。 如果有人在执行非阻塞计算时中断了线程(例如在cleanUp()内部),则不会立即中断此类计算。 但是,线程被标记为已中断,并且随后的所有阻塞操作(例如sleep() )都将立即立即抛出InterruptedException因此我们不会丢失该信号。

如果我们编写仍想利用线程中断功能的非阻塞线程,我们也可以利用这一事实。 不必依赖于InterruptedException我们只需定期检查Thread.isInterrupted()

public void run() {while (Thread.currentThread().isInterrupted()) {someHeavyComputations();}
}

在上方,如果有人中断了我们的线程,则在someHeavyComputations()返回时我们将立即放弃计算。 如果它运行了两个长时间或无限期,我们将永远不会发现中断标志。 有趣的是, interrupted标志不是一次性的 。 我们可以调用Thread.interrupted()而不是isInterrupted() ,这将重置interrupted标志并且我们可以继续。 有时您可能想忽略中断标志并继续运行。 在这种情况下, interrupted()可能会派上用场。 顺便说一句,我(不精确地)将“吸气剂”称为“ Heisengetters ”,它改变了被观察物体的状态 。

注意

如果您是老派程序员,您可能会想起Thread.stop()方法,该方法已被弃用10年了 。 在Java 8中,有计划“取消实现它” ,但在1.8u5中它仍然存在。 但是,不要使用它,而是使用Thread.stop()将任何代码重构为Thread.interrupt()

番石榴的

您很少会完全忽略InterruptedException 。 在这种情况下,请查看番石榴的《 Uninterruptibles 。 它具有许多实用方法,如sleepUninterruptibly()awaitUninterruptibly(CountDownLatch) 。 只是要小心他们。 我知道他们没有声明InterruptedException (可能很少),但是它们也完全防止了当前线程的中断–这是非常不寻常的。

摘要

到现在为止,我希望您对为什么某些方法引发InterruptedException有所了解。 主要的收获是:

  • 捕获的InterruptedException应该得到正确处理-大多数情况下,这意味着完全脱离当前任务/循环/线程
  • 吞下InterruptedException很少是一个好主意
  • 如果线程不在阻塞调用中而被中断,请使用isInterrupted() 。 当线程已经被中断时也进入阻塞方法应该立即抛出InterruptedException

翻译自: https://www.javacodegeeks.com/2014/06/interruptedexception-and-interrupting-threads-explained.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

映射网络驱动器会自动断开的解决方法

映射的网络驱动器在一段时间自动断开,是由于服务器服务自动断开连接功能的默认超时期限造成的,我们可以通过以下两种方法来更改断开时间: 方法一:修改注册表编辑相应的键值来增加默认超时期限在注册表中找到下面的注册表项&#x…

一行上自动控制数据长度,并换行

有的在开发中,遇到传来的数据太长,渲染到页面上会超出可视页面,出现横向滚动条,想解决一个办法就是数据到一定程度换行。 div{word-wrap: break-word;word-break: break-all;width:90%; /*可以根据情况调整*/ } 更多专业前端知识…

springboot(十)-监控应用

微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务的处理和传递,出现了异常如何快速定位是哪个环节出现了问题? 在这种框…

【概率DP】$P2059$ 卡牌游戏

【概率DP】P2059 卡牌游戏 链接 题目描述 N个人坐成一圈玩游戏。一开始我们把所有玩家按顺时针从1到N编号。首先第一回合是玩家1作为庄家。每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄…

基于角色的访问控制'的权限管理的数据库的设计实现

RBAC基于角色的访问控制的权限管理系统数据库设计与实现 use [master] go -- 检查数据库 [RBAC]是否存在,如果存在则删除(只测试用,不然会丢数据.) -- Search from the sysdatabase to see that if the [RBAC] database exist. -- If exists then drop it else create it. if…

Thymeleaf –片段和angularjs路由器局部视图

百里香叶许多很酷的功能之一就是能够渲染模板片段–我发现这是与AngularJs一起使用的特别有用的功能。 可以将AngularJS $ routeProvider或AngularUI路由器配置为返回不同“路径”的部分视图,使用百里香叶返回这些部分视图确实效果很好。 考虑一个简单的CRUD流&am…

web3.js_1.x.x--API(一)event/Constant/deploy/options

/* 事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调。事件在合约中可被继承。当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。 这些日志与合…

1022: 淘金(2017年中南大学研究生复试机试题 )

1022: 淘金 时间限制: 1 Sec 内存限制: 128 MB提交: 205 解决: 75[提交] [状态] [讨论版] [命题人:外部导入]题目描述 在一片n*m的土地上,每一块1*1的区域里都有一定数量的金子。这一天,你到这里来淘金,然而当地人告诉你,如果你…

CSS 定位 四种定位

absolute 生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。元素的位置通过“left”,“top”,“right”以及“bottom”属性进行定位。fixed 生成固定定位的元素,相对于浏览器窗口进行定位。元素的位置通过“left…

Apache CXF 3.0:CDI 1.1支持可替代Spring

在几周前刚刚发布Apache CXF 3.0时 ,该项目又迈出了满足JAX-RS 2.0规范要求的又一个重要步骤:与CDI 1.1集成。 在此博客文章中,我们将看几个有关Apache CXF 3.0和Apache CXF 3.0如何协同工作的示例。 从3.0版开始, Apache CXF包含…

用堆来求中位数

维护一个大根堆和一个小根堆。使得大根堆堆顶(最大的元素)比小根堆堆顶(最小的元素)小,且两个堆的元素个数的差小于等于1。这样元素多的那个堆的堆顶就是已读入数的中位数。如果读入偶数个数,则中位数为两个…

JPA 2.1类型转换器–保留枚举的更好方法

可以使用JPA 2.0保留枚举,但是没有很好的方法来实现。 使用Enumerated批注,可以使用EnumType.ORDINAL或EnumType.STRING将枚举值映射到其数据库表示形式。 但是这两种选择都有一些缺点,我们将在本文的第一部分中进行讨论。 在第二部分中&…

LOADRUNNER8.1中文版加10000客户端破解补订

http://www.17testing.com/download/LR_8.1.iso LOADRUNNER8.1 用迅雷下载http://www.17testing.com/download/LR_8.1ChinesePack.iso 中文包http://blog.chinaunix.net/upfile/070509151030.rar 10000客户端的破解补丁 LR 8.1的介质可以从这里下载:http://www.17t…

css布局笔记(二)Flex

flex Flex是“Flexible Box”的缩写,意为“弹性布局”,用来为盒状模型提供最大的灵活性。 任何一个容器都可指定为Flex布局。 .box{display:flex;} 行内元素也可以使用flex布局。 .box{display:inline-flex;} webkit内核的浏览器,必须加上-w…

BZOJ3709 Bohater 贪心

传送门 思路很妙…… 有个前提条件:血量无限,这样话肯定先打会回血的怪,再打会掉血的怪 对于会回血的怪,按照受到伤害的顺序从小往大打 对于会掉血的怪似乎并不是很好搞,考虑:将每一时刻的血量函数画出来&a…

反射与二次加工标准类型

反射与二次加工标准类型一、反射 反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。 有四个可以实现自省(反射)的函数,如下表所示: 函数名含义hasattr(object,name)判断object中有没有一个name字符串对应的方法或属性getattr(object,na…

Java 8 StampedLocks与ReadWriteLocks和同步

同步部分就像访问您的岳父母。 您希望尽可能少出现。 关于锁定,规则是相同的–您想花费最短的时间在关键区域内获取锁定,以防止形成瓶颈。 锁定的核心语言惯用法一直是用于方法和离散块的synced关键字。 这个关键字实际上已硬连接到HotSpot JVM中。 我们…

MSN on 2/16/2009

转载于:https://www.cnblogs.com/zxlin25/archive/2009/02/16/1391207.html

开发微信小程序中SSL协议的申请、证书绑定、TLS 版本处理等

在上篇随笔《基于微信小程序的系统开发准备工作》介绍了开发微信小程序的一些前期的架构设计、技术路线 、工具准备等方面内容,本篇随笔继续这个步骤,逐步介绍我们实际开发过程中对SSL协议的申请及后期处理过程,包括证书的IIS端口绑定&#x…

POJ 3253 Fence Repair

POJ 3253 Fence Repair 题目链接:http://poj.org/problem?id3253 题目大意 农夫约翰想修理牧场周围的一小段篱笆。他测量了栅栏,发现他需要N(1≤N≤20,000)块木板,每块长度为整数Li(1≤Li≤50,000)。然后,他买了一块长木板&#…