| 好看请赞,养成习惯

你有一个思想,我有一个思想,我们交换后,一个人就有两个思想

If you can NOT explain it simply, you do NOT understand it well enough

现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star


横看成岭侧成峰,远近高低各不同,并发编程理论系列基本已经结束,相信大家有了理论的铺垫,近看源码才能发现其设计之美,不会一头雾水


本来是要介绍 AQS 作为我们走进并发编程源码环节的第一步,但 AQS 涉及的知识点也还真有点多,每一个都够单独拿出来说一说,恰巧有朋友私信我“不理解线程的中断机制”,中断机制又恰巧是 AQS API实现的一部分,更贯穿于整个并发编程内容中。于是就打算单独说一说这个小机制,先让大家做到心中有 number

在学习/编写并发程序时,总会听到/看到如下词汇:

  • 线程被中断或抛出InterruptedException
  • 设置了中断标识
  • 清空了中断标识
  • 判断线程是否被中断

在 Java Thread 类又提供了长相酷似,让人傻傻分不清的三个方法来处理并发中断问题:

  • interrupt()
  • interrupted()
  • isInterrupted()

看到这我不禁会问自己:

什么是中断机制?

刚刚接触【中断】这个词时,先入为主的概念就是“直接中断/打断”正在做的事,使其停止。我的理解是这样的:

你:在打游戏

女朋友:别打游戏了,赶快过来吃饭

你:听到女朋友招呼之后立马中断手中的游戏乖乖过去吃饭

在多线程编程中,中断是一种【协同】机制,怎么理解这么高大上的词呢?就是女朋友叫你吃饭,你收到了中断游戏通知,但是否马上放下手中的游戏去吃饭看你心情 。在程序中怎样演绎这个心情就看具体的业务逻辑了,Java 的中断机制就是这么简单

如果还没改变这个先入为主的概念,我怀你你没有女朋友, 我们拥抱一下

为什么会有中断机制?

中断是一种协同机制,我觉得就是解决【当局者迷】的状况

现实中,你努力忘我没有昼夜的工作,如果再没有人告知你中断,你身体是吃不消的。

在多线程的场景中,有的线程可能迷失在怪圈无法自拔(自旋浪费资源),这时就可以用其他线程在恰当的时机给它个中断通知,被“中断”的线程可以选择在恰当的时机选择跳出怪圈,最大化的利用资源

那程序中如何中断?怎样识别是否中断?又如何处理中断呢?这就与上文提到的三个方法有关了

interrupt() VS isInterrupted() VS interrupted()

Java 的每个线程对象里都有一个 boolean 类型的标识,代表是否有中断请求,可你寻遍 Thread 类你也不会找到这个标识,因为这是通过底层 native 方法实现的。

interrupt()

interrupt() 方法是 唯一一个 可以将上面提到中断标志设置为 true 的方法,从这里可以看出,这是一个 Thread 类 public 的对象方法,所以可以推断出任何线程对象都可以调用该方法,进一步说明就是可以一个线程 interrupt 其他线程,也可以 interrupt 自己。其中,中断标识的设置是通过 native 方法 interrupt0 完成的

在 Java 中,线程被中断的反应是不一样的,脾气不好的直接就抛出了 InterruptedException() ,

该方法注释上写的很清楚,当线程被阻塞在:

  1. wait()
  2. join()
  3. sleep()

这些方法时,如果被中断,就会抛出 InterruptedException 受检异常(也就是必须要求我们 catch 进行处理的)

熟悉 JUC 的朋友可能知道,其实被中断抛出 InterruptedException 的远远不止这几个方法,比如:

反向推理,这些可能阻塞的方法如果声明有 throws InterruptedException , 也就暗示我们它们是可中断的

调用 interrput() 方法后,中断标识就被设置为 true 了,那我们怎么利用这个中断标识,来判断某个线程中断标识到底什么状态呢?

isInterrupted()

这个方法名起的非常好,因为比较符合我们 bean boolean 类型字段的 get 方法规范,没错,该方法就是返回中断标识的结果:

  • true:线程被中断,
  • false:线程没被中断或被清空了中断标识(如何清空我们一会看)

拿到这个标识后,线程就可以判断这个标识来执行后续的逻辑了。有起名好的,也有起名不好的,就是下面这个方法:

interrupted()

按照常规翻译,过去时时态,这就是“被打断了/被打断的”,其实和上面的 isInterrupted() 方法差不多,两个方法都是调用 private 的 isInterrupted() 方法, 唯一差别就是会清空中断标识(这是从方法名中怎么也看不出来的)

因为调用该方法,会返回当前中断标识,同时会清空中断标识,就有了那一段有点让人迷惑的方法注释:

来段程序你就会明白上面注释的意思了:

Thread.currentThread().isInterrupted(); // trueThread.interrupted() // true,返回true后清空了中断标识将其置为 falseThread.currentThread().isInterrupted(); // falseThread.interrupted() // false

这个方法总觉得很奇怪,现实中有什么用呢?

当你可能要被大量中断并且你想确保只处理一次中断时,就可以使用这个方法了

该方法在 JDK 源码中应用也非常多,比如(后续文章会具体分析,这里知道该方法的作用和使用场景就好):

相信到这里你已经能明确分辨三胞胎都是谁,并发挥怎样的作用了,那么有哪些场景我们可以使用中断机制呢?

中断机制的使用场景

通常,中断的使用场景有以下几个

  • 点击某个桌面应用中的关闭按钮时(比如你关闭 IDEA,不保存数据直接中断好吗?);
  • 某个操作超过了一定的执行时间限制需要中止时;
  • 多个线程做相同的事情,只要一个线程成功其它线程都可以取消时;
  • 一组线程中的一个或多个出现错误导致整组都无法继续时;

因为中断是一种协同机制,提供了更优雅中断方式,也提供了更多的灵活性,所以当遇到如上场景等,我们就可以考虑使用中断机制了

使用中断机制有哪些注意事项

其实使用中断机制无非就是注意上面说的两项内容:

  1. 中断标识
  2. InterruptedException

前浪已经将其总结为两个通用原则,我们后浪直接站在肩膀上用就可以了,来看一下这两个原则是什么:

原则-1

如果遇到的是可中断的阻塞方法, 并抛出 InterruptedException,可以继续向方法调用栈的上层抛出该异常;如果检测到中断,则可清除中断状态并抛出 InterruptedException,使当前方法也成为一个可中断的方法

原则-2

若有时候不太方便在方法上抛出 InterruptedException,比如要实现的某个接口中的方法签名上没有 throws InterruptedException,这时就可以捕获可中断方法的 InterruptedException 并通过 Thread.currentThread.interrupt() 来重新设置中断状态。

再通过个例子来加深一下理解:

本意是当前线程被中断之后,退出while(true), 你觉得代码有问题吗?(先不要向下看)

Thread th = Thread.currentThread();while(true) {  if(th.isInterrupted()) {    break;  }  // 省略业务代码  try {    Thread.sleep(100);  }catch (InterruptedException e){    e.printStackTrace();  }}

打开 Thread.sleep 方法:

sleep 方法抛出 InterruptedException后,中断标识也被清空置为 false,我们在catch 没有通过调用 th.interrupt() 方法再次将中断标识置为 true,这就导致无限循环了

这两个原则很好理解。总的来说,我们应该留意 InterruptedException,当我们捕获到该异常时,绝不可以默默的吞掉它,什么也不做,因为这会导致上层调用栈什么信息也获取不到。其实在编写程序时,捕获的任何受检异常我们都不应该吞掉

JDK 中有哪些使用中断机制的地方呢?

中断机制贯穿整个并发编程中,这里只简单列觉大家经常会使用的,我们可以通过阅读JDK源码来进一步了解中断机制以及学习如何使用中断机制

ThreadPoolExecutor

ThreadPoolExecutor 中的 shutdownNow 方法会遍历线程池中的工作线程并调用线程的 interrupt 方法来中断线程

FutureTask

FutureTask 中的 cancel 方法,如果传入的参数为 true,它将会在正在运行异步任务的线程上调用 interrupt 方法,如果正在执行的异步任务中的代码没有对中断做出响应,那么 cancel 方法中的参数将不会起到什么效果

总结

到这里你应该理解Java 并发编程中断机制的含义了,它是一种协同机制,和你先入为主的概念完全不一样。区分了三个相近方法,说明了使用场景以及使用原则,同时又给出JDK源码一些常见案例,相信你已经胸中有沟壑了,接下来,跟上节奏,我们陆续走进源码吧

灵魂追问

  1. 抛出 InterruptedException 后,中断标识就一定被清空吗?
  2. 处在死锁状态的线程是否可以被中断呢?
  3. 进入临界区的线程能否被中断呢?如果不能有什么办法能响应中断吗?
  4. 个人感觉interrupted这个方法名称不是特别好,如果你也觉得不好,让你设计这个地方,你有什么想法?

有朋友可能会问文章开头的图,同时看一个类的不同部分怎么实现的?不等您开口,我就全盘的招了,其实就是屏幕分割(在文件上鼠标右键->选择水平/垂直分割),这样在同时查看某些代码时还是很方便的(带鱼屏垂直分割真是爽翻天),保姆式演示如下:

参考

  1. Java 并发编程实战
  2. Java并发编程的艺术
  3. https://www.infoq.cn/article/java-interrupt-mechanism
  4. https://coderanch.com/t/237332/certification/explain-interrupt-isInterrupted-interrupted-method
  5. https://dzone.com/articles/waiting-for-coroutines 趣味原创解析Java技术栈问题,将复杂问题简单化,将抽象问题图形化落地 如果对我的专题内容感兴趣,或抢先看更多内容,欢迎访问我的博客 dayarch.top

java 并发_Java并发编程中断机制 so easy相关推荐

  1. java线程池并发_Java并发教程–线程池

    java线程池并发 Java 1.5中提供的最通用的并发增强功能之一是引入了可自定义的线程池. 这些线程池使您可以对诸如线程数,线程重用,调度和线程构造之类的东西进行大量控制. 让我们回顾一下. 首先 ...

  2. java 并发_Java并发防范机制

    1.背景 并发程序开发不可避免地要涉及多线程.多线程协作.数据共享和线程安全等问题.在多线程并发场景下,由于采用数据共享的线程通信模型可能导致多个线程之间并发时相互干扰,影响到程序的正常逻辑.无法保证 ...

  3. java 并行_Java 并行编程!

    多核处理器现在已广泛应用于服务器.台式机和便携机硬件.它们还扩展到到更小的设备,如智能电话和平板电脑.由于进程的线程可以在多个内核上并行执行,因此多核处理器为并发编程打开了一扇扇新的大门.为实现应用程 ...

  4. 判断三角形java代码_java基础编程题之异常处理

    以下是刚开始学习java的基础编程题,每天持续更新java每个知识点的题目,持续练习,不断提高java基本功,培养编程能力.今天的练习的十八题是java的异常处理的使用. 1.检测年龄不能为负数和大于 ...

  5. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  6. java赋值语句_java并发编程之原子性问题

    程序是否线程安全,取决于哪些要素呢,主要是以下三个: 原子性, 可见性, 有序性. 今天先一起来学习原子性. 原子性: 我理解一个操作不可再分,即为原子性.而在并发编程的环境中,原子性的含义就是只要该 ...

  7. java 并_java并发编程(一)

    java并发编程(一) 引言 多线程的知识点是一个庞大的体现,对此也是一知半解.一直想系统的深入的学习多线程的知识,奈何一直没有找到机会,好吧,其实就是懒.最近在项目中接触到一个多并发的项目,在项目中 ...

  8. java 可见性_Java并发编程-volatile可见性详解

    前言 要学习好Java的多线程,就一定得对volatile关键字的作用机制了熟于胸.最近博主看了大量关于volatile的相关博客,对其有了一点初步的理解和认识,下面通过自己的话叙述整理一遍. 有什么 ...

  9. java 银行并发_java并发编程——通过ReentrantLock,Condition实现银行存取款

    Java 并发编程系列文章 java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器.该框架允许更灵活地使用锁和条件,但以更难用的语法为代价 ...

最新文章

  1. Android 中的安全机制
  2. 美国五大科技巨头的人工智能竞赛
  3. 华为交换机网络管理相关配置问题(1)
  4. sql 语句中的 NULL值
  5. Oracle从零开始04——SQL语句03——单行函数
  6. 获取用户真实Ip地址
  7. (解决)mysql1366中文显示错误的终极解决方案
  8. 优秀开源项目:MyXls
  9. leetcode226 反转二叉树
  10. graphics | 基础绘图系统(十)——星形图、四瓣图、马赛克图
  11. 火车票放票时间 潜规则
  12. 中国城市电话区号对照表,不包括台湾
  13. 百练:2408:Anagram Groups
  14. linux磁盘所有格式化命令,Linux磁盘格式化命令的详细说明
  15. python提取excel一列或多列数据另存为新表(1)
  16. Pingouin: 基于pandas和numpy的统计包
  17. Error Domain=NSCocoaErrorDomain Code=3840 The operation couldn’t be completed. (Cocoa error 3840.)
  18. no matching host key type found. Their offer: ssh-rsa
  19. 小学学计算机应该学什么礼物,小学生毕业送什么礼物好?小学毕业礼物排行榜推荐...
  20. “我们的开源项目”发起人、息壤开源社区共同创始人——程旭文专访

热门文章

  1. 为啥计算机课要带u盘,电脑课上,student 关掉以后会不会被老师发现,同时电脑机上,老师不知干了什么,U盘没法使用,求解...
  2. java自动转换需要的开头_字符串和数值型进行运算时,字符串如果不是数字开头,会自动转换成什么?...
  3. Mybatis 一连串提问,被面试官吊打了!
  4. 万万没想到,JVM内存区域的面试题也可以问的这么难?
  5. 上班划水神器:一个可以在控制台玩斗地主的项目!
  6. jsp实现仿QQ空间新建多个相册名称,向相册中添加照片
  7. c 读取mysql 并显示_c/c++ mysql读取操作实现简单操控电脑
  8. python写一个crm系统_用Python打造一个CRM系统(四)
  9. IView的Form表单自定义验证需注意事项
  10. java基础面试题之:switch的参数类型