【JUC-Interrupt】中断相关概念

线程中断

  • 一、相关概念
  • 二、API
    • 2.1、isInterrupted方法
    • 2.2、interrupted方法
    • 2.3、interrupt
  • 三、总结:

一、相关概念

一个线程不应该由其他线程中断或停止,应该有线程自己来决定。

在Java中没有办法立即停止一个线程,因此提供了用于停止线程的协商机制中断

Java并没有给中断提供额外的语法,中断过程完全需要程序员自己实现,调用相关API如interrupt,也仅仅是将中断标志位设置为true

以实际例子体验一下:运行一个线程t1,线程t2打断t1的执行。

有三种实现方式:

  • volatilevolatile声明的变量,当值修改之后,其他线程立即可见。
  • AtomicBooleanAtomicBoolean本身就有原子性,不会出现线程安全问题,因此可以用于判断。
  • interrupt

先看volatile实现:

static volatile boolean isStop = false
private static void byVolatile() {new Thread(()->{// 模拟一直工作while (true) {if (isStop) {System.out.println("检测到中断信号,程序停止");break;}System.out.println("working.....");}}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{isStop = true;}, "t2").start();}

AtomicBoolean

static AtomicBoolean stop = new AtomicBoolean(false);
private static void byInterrupt() {var t1 = new Thread(()->{while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("检测到中断信号,程序停止");break;}System.out.println("working.....");}}, "t1");t1.start();try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{t1.interrupt(); // 打断t1}, "t2").start();}

通过默认的interrupt机制:

private static void byInterrupt() {var t1 = new Thread(()->{while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("检测到中断信号,程序停止");break;}System.out.println("working.....");}}, "t1");t1.start();try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{t1.interrupt(); // 在t2线程中打断t1}, "t2").start();}

二、API

中断中有三个比较重要的API:interrupt()isInterrupted()interrupted()
在这里插入图片描述

2.1、isInterrupted方法

源码如下:

    public boolean isInterrupted() {return interrupted;}

注释:
Tests whether this thread has been interrupted. The interrupted status of the thread is unaffected by this method.
测试并获取当前线程的中断状态。

2.2、interrupted方法

    public static boolean interrupted() {Thread t = currentThread();boolean interrupted = t.interrupted;// We may have been interrupted the moment after we read the field,// so only clear the field if we saw that it was set and will return// true; otherwise we could lose an interrupt.if (interrupted) {t.interrupted = false;clearInterruptEvent();}return interrupted;}

源码注释:

Tests whether the current thread has been interrupted. The interrupted status of the thread is cleared by this method. In other words, if this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it).

简单来说就是:

  1. 如果当前中断标志是true, 那么会返回true并清除当前状态标志,也就是设置为false
  2. 如果当前是false,那么会返回false
  3. 如果在中断标志为true的情况下,连着执行两次,结果依次为truefalse

2.3、interrupt

   public void interrupt() {if (this != Thread.currentThread()) {// Determines if the currently running thread has permission to modify this threadcheckAccess();// thread may be blocked in an I/O operationsynchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupted = true;interrupt0();  // inform VM of interruptb.interrupt(this);return;}}}interrupted = true;// inform VM of interruptinterrupt0();}

这段代码上注释挺多的,我们慢慢读:

Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

翻译一下:

如果执行这个方法的线程不是本身(因为别的线程也能调用你的这个方法),将会调用checkkAccess方法检查调用者是否有权限调用,没有的话会返回SecurityException

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int) methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

翻译一下,这里很重要:

如果当前线程因为Object中的waitThead中的join、sleep方法阻塞,当调用interrupt方法的时候,会清除当前的标志位,并报InterruptedException 异常。

如果编程的时候没有注意上面这一点,可能没有办法中断线程,引起不可预知的错误。

If this thread is blocked in an I/ O operation upon an InterruptibleChannel then the channel will be closed, the thread’s interrupt status will be set, and the thread will receive a java. nio. channels. ClosedByInterruptException.

翻译:

如果线程因为I/O操作阻塞,调用interrupt将会设置中断位,但是会报一个错误

If this thread is blocked in a java. nio. channels. Selector then the thread’s interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector’s wakeup method were invoked

NIO部分不太清楚,大致意思也是会设置中断位。

If none of the previous conditions hold then this thread’s interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.

翻译一下:

如果没有上述情况发生,线程中断标志位将会被正确设置

中断一个不活动的线程不会产生任何影响

下面用案例演示一下阻塞的时候调用interrupt会出现的问题:

下面是t1线程:

// 线程t1
Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName() + " 中断标志位为:" + Thread.currentThread().isInterrupted() + " 程序停止");break;}try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("-------------hello InterruptDemo3");}
}, "t1");
t1.start();try {TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {e.printStackTrace();
}

看到t1的逻辑很简单,如果没有检测到中断标志位,会模拟200ms延迟,然后打印语句。

假如线程启动1s之后,来个t2线程,在执行体中中断了t1, 会不会发生我们上面学到的清空标志位呢?

 new Thread(() -> {t1.interrupt();}, "t2").start();

运行之后会发现,控制台报了异常,但是t1线程没有停止运作,因为在发生异常的时候,interrupt status已经被清除了,导致if 循环检测不到了,程序一直运行下去…

正确的做法是,在Object.wait, Thread.join(), Thread.sleep()catch块中,自己将中断标志位设置为true,防止上面错误:

// 线程t1
Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName() + " 中断标志位为:" + Thread.currentThread().isInterrupted() + " 程序停止");break;}//sleep方法抛出InterruptedException后,中断标识也被清空置为false,如果没有在//catch方法中调用interrupt方法再次将中断标识置为true,这将导致无限循环了try {Thread.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 自己打断自己e.printStackTrace();}System.out.println("-------------hello InterruptDemo3");}
}, "t1");

三、总结:

方法名作用
isInterrupted返回当前线程的中断标志位 ,注意:如果当前线程是不活跃状态(执行完了),在JDK8中,会自动将中断标志位设置为false,在JDK17中,不会清除中断标志位,也就是说,打断了某个线程,即便是线程执行完毕,调用此方法获得的结果仍旧是true
interrupted静态方法,做两件事情:返回当前中断标志位并清除中断标志位(设为false)
interrupt设置中断标志位为true, 在阻塞的情况下可能会导致无法中断线程的情况,要在catch块中设置中断

解释一下上面的注意

/*** 执行interrupt方法将t1标志位设置为true后,t1没有中断,仍然完成了任务后再结束* 2000毫秒后,t1线程已经结束了,如果是JDK8,会自动恢复为false,JDK17则不会自动恢复标志。*/
public class InterruptDemo2 {public static void main(String[] args) {//实例方法interrupt()仅仅是设置线程的中断状态位为true,不会停止线程Thread t1 = new Thread(() -> {for (int i = 1; i <= 300; i++) {System.out.println("------: " + i);}/*** ------: 298* ------: 299* ------: 300* t1线程调用interrupt()后的中断标志位02:true*/System.out.println("t1线程调用interrupt()后的中断标志位02:" + Thread.currentThread().isInterrupted());}, "t1");t1.start();System.out.println("t1线程默认的中断标志位:" + t1.isInterrupted());//falsetry {TimeUnit.MILLISECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}t1.interrupt();//true/*** ------: 251* ------: 252* ------: 253* t1线程调用interrupt()后的中断标志位01:true*/System.out.println("t1线程调用interrupt()后的中断标志位01:" + t1.isInterrupted());//truetry {TimeUnit.MILLISECONDS.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//2000毫秒后,t1线程已经结束了,如果是JDK8,会自动恢复为false// JDK17则不会自动恢复标志。System.out.println("t1线程调用interrupt()后的中断标志位03:" + t1.isInterrupted());//true (笔者用的JDK17)}
}

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

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

相关文章

javascript基础学习

什么是伪代码 伪代码(Pseudocode)是一种介于自然语言和编程语言之间的算法描述方式。它使用类似自然语言的语句来描述程序的逻辑和流程,但又采用了编程语言中的一些结构和控制语句,如循环、条件判断等。 伪代码的目的是在不涉及具体编程语言语法细节的情况下,清晰地表达…

Django+Nginx+uwsgi网站Channels+redis+daphne多人在线聊天实现粘贴上传图片

在DjangoNginxuwsgi网站Channelsredisdaphne多人在线的基础上&#xff08;详见DjangoNginxuwsgi网站使用Channelsredisdaphne实现简单的多人在线聊天及消息存储功能-CSDN博客&#xff09;&#xff0c;实现在输入框粘贴或打开本地图片&#xff0c;上传到网站后返回图片路径&…

C++ —— 以真我之名 如飞花般绚丽 - 智能指针

目录 1. RAII和智能指针的设计思路 2. C标准库智能指针的使用 2.1 auto_ptr 2.2 unique_ptr 2.3 简单模拟实现auto_ptr和unique_ptr的核心功能 2.4 shared_ptr 2.4.1 make_shared 2.5 weak_ptr 2.6 shared_ptr的缺陷&#xff1a;循环引用问题 3. shared_ptr 和 unique_…

vulnhub靶场之breakout

empire靶场2 前言 靶机&#xff1a;breakout 攻击&#xff1a;kali 续接上个靶场empire1的继续学习 主机发现 使用arp-scan扫描或者直接查看虚拟机的ip地址 信息收集 使用nmap扫描 端口80apache 2.4.51开启smb服务的两个端口139、445&#xff0c;版本4.6.2两个http服务采…

今天你学C++了吗?——C++中的类与对象(第二集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

聚划算!一区算法!双分解+牛顿拉夫逊优化+深度学习!CEEMDAN-VMD-NRBO-Transformer多元时序预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CEEMDAN-Kmeans-VMD-NRBO-Transformer融合K均值聚类的数据双重分解牛顿-拉夫逊优化算法Transformer多元时间序列预测&#xff08;完整源码和数据&#xff09;运行环境Matlab2023b及以上。 2.CEEMDAN分解…

C++设计模式-中介者模式

动机(Motivation) 多个对象相互关联的情况&#xff0c;对象之间常常会维持一种复杂的引用关系&#xff0c;如果遇到一些需求的更改&#xff0c;这种直接的引用关系将面临不断的变化。在这种情况下&#xff0c;可以使用一种”中介对象“来管理对象间的关联关系&#xff0c;避免…

滑动窗口篇——如行云流水般的高效解法与智能之道(2)

前言&#xff1a; 上篇我们介绍了滑动窗口的含义并结合基础题型加以练习&#xff0c;本篇将以进阶难度的题目为索引&#xff0c;深化对于滑动窗口的运用与理解。 一. 将x减到0的最小操作数 题目链接&#xff1a;1658. 将 x 减到 0 的最小操作数 - 力扣&#xff08;LeetCode&am…

EG3D: Efficient Geometry-aware 3D Generative Adversarial Networks 学习笔记

1 Contributions 混合显式-隐式网络架构&#xff1a;提出了一种 Tri-plane 的3D表征方法&#xff0c;结合显式体素网格与隐式解码器的优点 速度快&#xff0c;内存效率高&#xff1b; 支持高分辨率生成&#xff0c;保持3D表征的灵活性和表达能力。与纯显式或隐式方法相比&#…

⭐ Unity 资源管理解决方案:Addressable_ Demo演示

一、使用Addressable插件的好处&#xff1a; 1.自动管理依赖关系 2.方便资源卸载 3.自带整合好的资源管理界面 4.支持远程资源加载和热更新 二、使用步骤 安装组件 1.创建资源分组 2.将资源加入资源组 3.打包资源 4.加载资源 三种方式可以加载 using System.Collections…

C++《二叉搜索树》

在初阶数据结构中我学习了树基础的概念以及了解了顺序结构的二叉树——堆和链式结构二叉树该如何实现&#xff0c;那么接下来我们将进一步的学习二叉树&#xff0c;在此会先后学习到二叉搜索树、AVL树、红黑树&#xff1b;通过这些的学习将让我们更易于理解后面set、map、哈希等…

使用VisualStudio编写C++程序输出helloWorld

文章目录 1. C简介1.1 历史背景1.2 特点1.3 应用领域 2. 操作过程和代码2.1 打开Visual Studio(默认你下载了C的相关文件)2.2 创建新项目2.3 输入名字&#xff0c;创建2.4 右击源文件->添加->新建项2.5 命名好&#xff0c;进行添加2.6 输入代码2.7 输出结果 3. 总结 1. C…

万能的无人机锁定目标投放程序

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

LayaBox1.8.4实现UV滚动

实现思路&#xff1a; 在片元着色器采样时&#xff0c;增加一个随时间变化的偏移值&#xff0c;由于uv是一个二维向量所以加的偏移值也需要一个二维向量。注意&#xff1a;在Laya的 shader中除了0&#xff0c;输入其它数字必须输入带有小数的数字&#xff0c;否则报错 。 &quo…

Next.js- App Router 概览

#题引&#xff1a;我认为跟着官方文档学习不会走歪路 一&#xff1a;App Router与Page Router 在 v13 版本中&#xff0c;Next.js 引入了一个基于 React 服务器组件 构建的新的 App Router&#xff0c;而在这之前&#xff0c;Next.js 使用的是Page Router。 目录结构 pages …

milvus es

ES 与 Milvus 结合实现高效文档搜索的实战指南 原文链接 目录 背景介绍场景与效果概述架构对比与问题分析Milvus 向量搜索架构ES Milvus 搜索架构详细流程解析Milvus 搜索配置详解ES 搜索策略与 DSL 配置结果合并与排序策略总结与未来优化 1. 背景介绍 随着团队和公司的发…

Flutter 设计模式全面解析:抽象工厂

设计模式作为软件开发中的经典解决方案&#xff0c;在 Flutter 的开发中也能为我们提供强大的架构支持。本文来介绍一下如何在 Flutter 中来实现抽象工厂设计模式&#xff0c;以及如何创建一系列相关或依赖对象并优雅地管理它们之间的复杂依赖关系。 日常开发中我们也能经常看…

『 Linux 』网络层 - IP协议 (二)

文章目录 路由NAT技术分片与组装分片的组装IP协议分片的短板 路由 通常情况路由器具备了一个非常重要的功能,即构建子网; 同时路由器需要实现跨网络通信,说明路由器必须存在两个或以上的IP地址,通常在路由器中可以看到几个接口,分别是一个WAN口和几个LAN口; WAN口IP被称为公网I…

深度学习实战图像缺陷修复

这里写目录标题 概述1. 图像缺陷修复的研究背景2. 传统图像缺陷修复方法的局限性(1) 基于纹理合成的方法(2) 基于偏微分方程&#xff08;PDE&#xff09;的方法 3. 深度学习在图像缺陷修复中的兴起(1) 深度学习的基本思路(2) 深度学习方法的优势(3) 关键技术的引入 4. 深度学习…

【SQL实验】索引操作(菜单操作和命令操作)

【代码是自己的解答&#xff0c;并非标准答案&#xff0c;也有可能写错&#xff0c;文中可能会有不准确或待完善之处&#xff0c;恳请各位读者不吝批评指正&#xff0c;共同促进学习交流】 文件”成绩管理”导入【具体操作前几篇文章详细展示过来&#xff0c;这里跳过。还是不太…