如果没有将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()可能会派上用场。 顺便说一句,我(不精确地)称“吸气剂”来改变被观察物体的状态 “ 海森格 ”。

注意

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

番石榴的

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

摘要

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

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

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

InterruptedException和中断线程的解释相关推荐

  1. InterruptedException和中断线程的说明

    如果没有将InterruptedException检查为异常,则可能甚至没人会注意到它-这实际上可以防止这些年来的几个错误. 但是由于必须对其进行处理,因此许多人不正确或不加考虑地处理它. 让我们以一 ...

  2. 为什么不推荐使用 stop、suspend 方法中断线程?

    以下文章来源方志朋的博客,回复"666"获面试宝典 作者 | 浪舟子 来源 | https://blog.csdn.net/qq_40400960/article/details/ ...

  3. sleep interrupted异常_Java高并发3中断线程以及isInterrupted与interrupted区别

    一.复习上一节内容 wait()方法.中断正在运行的线程会抛出java.lang.InterruptedException.当线程调用共享对象的wait()方法时,当前线程只会释放当前共享变量的锁,不 ...

  4. 为什么强烈不推荐使用stop、suspend方法来中断线程?

    点击关注公众号,实用技术文章及时了解  作者:浪舟子  blog.csdn.net/qq_40400960/article/details/112651249 我们知道像stop.suspend这几种 ...

  5. 【多线程】线程的引入,创建线程的方式,设置线程名字、获取名字,线程优先级priority,加入休眠的方法,,后台线程,礼让线程,Join,中断线程,某电影院,共有100张票线程流程图,3售票窗口,

    多线程 1.线程的引入 进程: 正在运行的程序,是系统进行资源分配和调用的独立单位.每一个进程都有它自己的内存空间和资源. 线程: 是进程的单个顺序控制流,或者说就是一个单独执行的路径 一个进程如果只 ...

  6. java 线程 通过interrupted_Java线程的传说(1)——中断线程Interrupted的用处

    中断线程 -- interrupt() 一个正在运行的线程除了正常的时间片中断之外,能否被其他线程控制?或者说其他线程能否让指定线程放弃CPU或者提前结束运行? 除了线程同步机制之外,还有两种方法: ...

  7. java中断线程_Java中断线程的方法

    使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回.这 ...

  8. c++并发编程实战_Java 并发编程实战:JAVA中断线程几种基本方法

    一个多线程Java程序,只有当其全部线程执行结束时(更具体地说,是所有非守护线程结束或者某个线程调用system.exit()方法的时候) ,才会结束运行.有时,为了终止程序或者取消一个线程对象所执行 ...

  9. java线程——中断线程+线程状态+线程属性(优先级)

    [0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程--中断线程+线程状态+线程属性(优先级) 的相关知识: [1]中断线程 1.1 ...

最新文章

  1. OC中创建对象,存入数组,并且遍历对象
  2. [转] 使用nginx sticky实现基于cookie的负载均衡
  3. python编程 语言-python编程语言有什么用途
  4. python类和对象介绍_python中的类,对象,方法,属性等介绍
  5. 年轻人(以我为例)最应该做的事情(个人观点)
  6. MongoDB(6.mongodb的聚合操作以及高级查询3、排序等)
  7. my.ini修改后服务无法启动_Spring Cloud Eureka 服务实现不停机(Zero-downtime)部署
  8. 【机器学习】sclearn分类算法-决策树、随机森林
  9. C++/C--字符串分割函数 --strtok()
  10. 苹果iOS 11.3.1正式发布,修复iPhone 8触屏bug
  11. redis zset怎么排序_redis(set、zset)类型使用和使用场景
  12. Opencv使用cv::matchTemplate进行模板匹配
  13. 宽带波束形成及MATLAB实现
  14. Bridge桥的简介-从零开始学RouterOS系列14
  15. 计算机系单身率排行榜,2020中国高校单身率排行榜出炉!附:单身率特别高的专业...
  16. 如何下载B站视频,解决视频没有声音/音画分离问题(IDM+Potplayer)
  17. 视频处理之浮雕效果【附源码】
  18. 嵌入式系统求职回忆录
  19. 2021阿里云学生服务器申请地址购买攻略及配置选择
  20. python编程题6-抓狐狸小游戏

热门文章

  1. P3368-Frequent values【线段树】
  2. 【前缀和】【DP】登机(jzoj 5535)
  3. codeforces G - Almost Increasing Array 动态规划、动态开点线段树
  4. Java的并发编程中的多线程问题到底是怎么回事儿?
  5. JAVA数据库连接池实现
  6. Mycat - 数据库分库分表中间件,国内最活跃的、性能最好的开源数据库中间件
  7. 如何安装并启动django
  8. Spring依赖注入和控制反转
  9. 第四章选择结构(二)
  10. JsonData响应工具类封装