【JavaEE多线程】线程中断 interrupt()

系列文章目录

🌈座右铭🌈:人的一生这么长、你凭什么用短短的几年去衡量自己的一生!

💕个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C++,自顶向下看Java-CSDN博客

❤️相关文章❤️:清灵白羽 漾情天殇-CSDN博客


目录

系列文章目录

一、终止一个线程

1、标记位终止线程

        1、定义一个共享的标记变量

        2、在线程的执行任务当中周期性检查标记

        3、提供公共方法来设置标记

        4、代码展示标记位终止线程

2、调用interrupt()方法

      1、interrupt()方法

      2、interrupted()方法

      3、isInterrupted()方法

      4、如何判断应该使用哪种方法呢?

      5、什么情况下需要清除中断状态,又为什么要清除中断状态呢?

拓展:

二、线程等待


一、终止一个线程

1、标记位终止线程

        在Java当中通过共享的标记位来终止线程是一种常见的方式,这种方式通常设计一个布尔类型的变量,通常被称为标记或者标志,用来指示线程是否应该终止,线程在执行任务的时候会周期性地检查这个标记,并且标记指示终止时主动退出执行。

        1、定义一个共享的标记变量

        

private volatile boolean shouldTerminate = false;

        这里使用了volatile这个关键字,后续我会为大家详细介绍这个关键字的用法,大家这里先暂时忽略它。

        2、在线程的执行任务当中周期性检查标记

        在线程的任务当中通过周期性地检查标记来确定是否应该被终止,通常在循环当中检查标记。

     

public void run() {while (!shouldTerminate) {// 执行任务}
}

        当这个标记位为true的时候,线程就会退出循环,从而终止执行任务。

        3、提供公共方法来设置标记

        在需要终止线程的时候,提供一个公共方法来设置标记为true。

public void requestTermination() {shouldTerminate = true;
}

        4、代码展示标记位终止线程

public class Main{private static class MyRunnable implements Runnable{private volatile boolean shouldTerminate = false;@Overridepublic void run() {while (!shouldTerminate){System.out.println("Thread is running...");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("Thread terminated...");}public void requestTermination(){shouldTerminate = true;}}public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}myRunnable.requestTermination();}
}

        在我的示例代码当中,MyRunnable类声明为静态内部类,有以下几个原因:

        1、静态内部类可以直接访问外部类的静态成员

        2、静态内部类的实例化不依赖外部类的实例

        3、静态内部类可以更方便地重用和单独测试:将M有Runnable声明为静态内部类可以使得它更容易被其它类重用,并且可以在不依赖外部类的情况下单独测试。

2、调用interrupt()方法

        我在这里要声明以下只有interrupt方法才能中断线程,其余两个方法只是检查线程当前的线程状态的,这里一定不要混淆。    

      1、interrupt()方法

  • interrupt()方法是Thread类的实例方法,用于向目标线程发送中断信号,即设置目标线程的中断状态为true。
  • 如果目标线程正在阻塞(如调用了sleep()wait()join()等方法),那么会抛出InterruptedException异常。
  • 如果目标线程正在运行,那么只是简单地设置其中断状态为true,线程需要在合适的时机自行检查中断状态并作出响应。

      2、interrupted()方法

        这里的方法其实就是系统为我们自动维护的一个标记位,不需要我们在手动维护了,一会我写代码各位就能够看懂了。

  • interrupted()是Thread类的静态方法,用于检查当前线程的中断状态,并清除中断状态(将中断状态重置为false)。
  • 如果当前线程的中断状态为true,则返回true;否则返回false。
  • interrupted()方法还可以用来检查其他线程的中断状态,即Thread.interrupted()会检查调用它的线程的中断状态。

        3、isInterrupted()方法

  • isInterrupted()是Thread类的实例方法,用于检查目标线程的中断状态,但不会清除中断状态。
  • 如果目标线程的中断状态为true,则返回true;否则返回false。
  • isInterrupted()方法可以用来检查其他线程的中断状态,即通过thread.isInterrupted()来检查指定线程的中断状态。

        总结:

  • interrupt()方法是设置线程中断状态为true的方法,用于向目标线程发送中断信号。
  • interrupted()方法是用于检查当前线程中断状态并清除中断状态。
  • isInterrupted()方法是用于检查目标线程中断状态,但不会清除中断状态。

        4、如何判断应该使用哪种方法呢?

  • 如果你希望向一个线程发送中断信号,让它在合适的时候自行终止执行,那么使用interrupt()方法是比较合适的。这种方式允许线程自行决定如何响应中断信号,可以更安全地终止线程的执行。

  • 如果你需要在一个线程中检查自身的中断状态,并清除中断状态,可以使用interrupted()方法。这种方式适合在执行任务的线程中周期性地检查中断状态,以便及时响应中断信号并执行相应的清理操作。

  • 如果你需要检查其他线程的中断状态,而且不想清除中断状态,可以使用isInterrupted()方法。这种方式适合在一个线程中检查其他线程的中断状态,例如在监控线程池中线程的执行情况时。

        5、什么情况下需要清除中断状态,又为什么要清除中断状态呢?

        清除中断状态通常发生在一些特定的情况下,这些情况通常涉及到线程的异常处理或者线程的复用。

        1、异常处理:在捕获了InterruptedException异常之后,需要清除线程的中断状态。

        2、线程复用:当一个线程执行完某个任务后,可能需要复用该线程来执行其他任务。

        清除中断状态就是将线程判断是否中断的标记位设置为初始值也就是false,清除中断状态就是告诉其它线程这个线程没有被中断。

        在Java中,当线程被中断时,它的中断状态会被设置为true。这个中断状态可以通过调用Thread.interrupted()isInterrupted()方法来检查。

        InterruptedException异常通常是在线程调用了一些可能会抛出InterruptedException的阻塞方法(例如Thread.sleep()、Object.wait()、Thread.join()等)时才会抛出。当线程处于阻塞状态(例如调用了上述方法),而且此时又接收到了中断请求时,这些阻塞方法会抛出InterruptedException异常。这样做的目的是让线程在阻塞状态中响应中断请求,从而提高线程的响应性。因为阻塞的线程无法响应中断请求这个时候抛出异常并且在抛出异常之前系统会自动清除中断状态,让这个目标线程以非中断的状态去响应这个中断。并不是所有的中断请求都会导致InterruptedException异常的抛出。如果线程正在执行非阻塞的任务,而此时接收到中断请求,那么线程就不会抛出InterruptedException异常,而是需要通过检查中断状态来判断是否应该终止执行。

        上述的interrupted()方法是手动清除中断状态,抛出异常这个操作是系统自动清除中断状态,不管怎样目的都是为了清除中断状态让线程继续执行剩余的业务逻辑。

public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();try {Thread.sleep(2000);thread.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}static class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("子线程开始执行...");try {Thread.sleep(5000);System.out.println("子线程睡眠结束...");} catch (InterruptedException e) {System.out.println("子线程被中断...");e.printStackTrace();}if (Thread.currentThread().isInterrupted()){System.out.println("未被清除!");}else {System.out.println("已被清除");}}}
}

拓展:

        

public class Main {private static class MyRunnable implements Runnable{@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()){System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("中断线程");}}System.out.println("线程已经中断");}}public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}thread.interrupt();}
}

        这段代码大家可以试着运行一下,调用interrupt()无法终止线程,当控制台输出中断线程之后,线程会继续执行,这是为什么呢?因为线程在休眠状态下sleep()的时候,系统为了让这个线程响应中断请求,会将他唤醒,并且在抛出异常之前自动清除这个线程的中断状态,也就是这个时候线程的标记位仍然为false,所以这个时候我们必须对这个线程的中断状态进行恢复或者直接使用break关键字终止线程,这里还是推荐大家使用恢复线程中断状态比较好,修改以后的代码如下:

Thread.currentThread().interrupt();

        只需要添加这一行代码即可:

public class Main {private static class MyRunnable implements Runnable{@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()){System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("中断线程");Thread.currentThread().interrupt();e.printStackTrace();}}System.out.println("线程已经中断");}}public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}thread.interrupt();}
}

        我们使用这行代码将线程的中断状态恢复,线程就可以顺利中断了。


二、线程等待

         

        join()方法是 Thread 类提供的一个方法,用于让一个线程等待另一个线程的结束。具体来说,当一个线程调用另一个线程的 join() 方法时,它会阻塞自己的执行,直到被等待的线程执行结束才继续执行。

这个方法提供了一种线程之间的协作机制,允许一个线程等待另一个线程完成某些重要的工作,然后再继续执行。它通常用于主线程等待子线程的完成,或者一个线程等待其他一组线程的完成。

join() 方法有多个重载形式:

  1. join():使当前线程等待被调用对象的执行完成。
  2. join(long millis):使当前线程等待被调用对象的执行完成,但最多等待指定的毫秒数。
  3. join(long millis, int nanos):使当前线程等待被调用对象的执行完成,但最多等待指定的毫秒数和纳秒数。

使用 join() 方法的一个常见模式是创建一个线程并启动它,然后在主线程中调用该线程的 join() 方法,以等待该线程的完成。例如:

public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动子线程try {thread.join(); // 主线程等待子线程执行完成} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程执行完成,主线程继续执行...");}static class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("子线程开始执行...");// 模拟子线程执行一些耗时操作try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程执行完成。");}}
}

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

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

相关文章

StarRocks最佳实践经验

目录 一、部署 1.1 容量规划 1.2 基础环境配置 1.3 机器配置 1.3.1 FE节点 1.3.2 BE节点 1.4 部署方案 二、建模 2.1 建表规范 2.2 模型选择 2.3 排序列和前缀索引选择 2.4 分区选择 2.5 分桶选择 2.6 字段类型 2.7 索引选择 2.7.1 Bitmap索引 2.7.2 Bloom fi…

debian8安装后无法使用博通无线网卡BCM43224,提示缺少固件

装完debian8后发现主机自带的无线网卡不能使用,并且在安装系统过程中会有提示: 您的一些硬件需要非自由固件文件才能运转。固件可以从移动介质加载。 缺失的固件文件是:brcm/brcm43xx-0.fw我没有理会,装完后发现无线网卡不能用 需要安装 broadcom-wl 查看网卡芯片型号 …

笔记本电脑耗电和发热比较厉害怎么处理

工作中会遇到有同事反馈笔记本电脑耗电和发热比较厉害,主要检查以下几个地方 1、CPU频率 很多人觉得是cpu使用率高就代表电脑跑得快,发热量就大,其实不是的,主要是看的cpu频率,频率越高,电脑发热量越大。如…

(N-151)基于微信小程序校园学生活动管理平台

开发工具:IDEA、微信小程序 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 前端技术:vue、uniapp 服务端技术:springbootmybatisplus 本系统分微信小程序和管理后台两部分&am…

探索开源的容器引擎--------------Docker容器操作

目录 一、Docker 容器操作 1.1容器创建 1.2查看容器的运行状态 1.3启动容器 1.4创建并启动容器 1.4.1当利用 docker run 来创建容器时, Docker 在后台的标准运行过程是: 1.4.2在后台持续运行 docker run 创建的容器 1.4.3创建容器并持续运行容器…

免费开源线上社交交友婚恋系统平台 可打包小程序 支持二开 源码交付!

婚姻是人类社会中最重要的关系之一,它对个人和家庭都有着深远的影响。然而,在现代社会的快节奏生活中,找到真爱变得越来越困难。在这个时候,婚恋产品应运而生,为人们提供了寻找真爱的新途径。 1.拓宽人际交流圈子 现代…

手撕netty源码(一)- NioEventLoopGroup

文章目录 前言一、NIO 与 netty二、NioEventLoopGroup 对象的创建过程2.1 创建流程图 前言 本文是手撕netty源码系列的开篇文章,会先介绍一下netty对NIO关键代码的封装位置,主要介绍 NioEventLoopGroup 对象的创建过程,看看new一个对象可以做…

【国产替代】航空电子通信总线航空电子通信总线产品为MIL-STD-1553和ARINC 429等协议提供原生支持

航空电子通信总线 航空电子通信总线产品为MIL-STD-1553和ARINC 429等协议提供原生支持。这些产品用于进行航空电子应用所需的开发、生产和系统测试。 PXIe,2通道PXI ARINC-664接口模块 AIM ARINC-664具有板载处理器,可自动处理所有与协议相关的活动&…

界面组件DevExpress Blazor UI v23.2 - 支持.NET 8、全新的项目模版

DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生Blazor UI组件(包括Pivot Grid、调度程序、图表、数据编辑器和报表等)。 DevExpress Blazor控件目前已经升级…

(五)AB测试及两个案例 学习简要笔记 #统计学 #CDA学习打卡

目录 一. AB测试简介 1)假设检验的一般步骤 2)基于假设检验的AB测试步骤 二. 案例1:使用基于均值的假设检验进行AB测试 1)原始数据 2)提出原假设H0和备择假设H1 3)使用均值之差的t检验,计…

AI视频改字个性化祝福豪车装X系统uniapp前端开源源码下载

装X系统源码简介 创意无限!AI视频改字祝福,豪车装X系统源码开源,打造个性化祝福视频不再难! 想要为你的朋友或家人送上一份特别的祝福,让他们感受到你的真诚与关怀吗?现在, 通过开源的AI视频…

【深度学习】yolo-World,数据标注,zeroshot,目标检测

仓库:https://github.com/AILab-CVC/YOLO-World 下载权重: 仓库下载和环境设置 下载仓库:使用以下命令从 GitHub 上克隆仓库: git clone --recursive https://github.com/AILab-CVC/YOLO-World.git创建并激活环境&#xff1a…

scipy csr_matrix: understand indptr

See https://stackoverflow.com/questions/52299420/scipy-csr-matrix-understand-indptr

架构师核心-云计算云上实战(云计算基础、云服务器ECS、云设施实战、云上高并发Web架构)

文章目录 云计算基础1. 概念1. 云平台优势2. 公有云3. 私有云4. IaaS、PaaS、SaaS 2. 云设施1. 概览2. 核心组件 云服务器ECS1. ECS介绍1. 简介2. 组件3. 概念4. 图解5. 规格6. 场景 2. ECS服务器开通1. 开通服务器2. 连接服务器 3. 云部署准备1. 1Panel介绍2. 安装1Panel3.安全…

梯度,hesse阵与Jacobi矩阵

分清楚三个量的含义和计算方法。 梯度 表征的是一个列向量,是相对于某个方向而言的,但是某个方向上可能有多个变量,所以梯度不是简单的直接求偏导,并且说了,它是一个列向量,所以, 我们设 f : …

ArcGIS Pro 和 Python — 分析全球主要城市中心的土地覆盖变化科林

第一步——设置工作环境 1–0. 地理数据库 在下载任何数据之前,我将创建几个地理数据库,在其中保存和存储所有数据以及我将创建的后续图层。将为我要分析的五个城市中的每一个创建一个地理数据库,并将其命名为: “Phoenix.gdb” “Singapore.gdb” “Berlin.gdb” “B…

[论文笔记] EcomGPT:COT扩充数据的电商大模型

社区供稿 | EcomGPT:基于任务链数据的电商大模型(附魔搭推理实践) - 知乎 https://arxiv.org/pdf/2312.15696.pdf EcomInstruct指令数据集构建 数据集组成 COT方式构造垂域训练数据:把原本的垂域任务分解成了原子任务,构造了基于解决原子任务的数据。这样能用类似…

ThingsBoard教程(二十九):详细讲解在tb平台下 http协议下的客户端rpc,服务的rpc的使用

客户端rpc 先来说一下简单的客户端rpc, 客户端发起rpc请求,只需要使用post方法调用该接口即可以 http://host:port/api/v1/$ACCESS_TOKEN/rpc请求路径中间的参数 ACCESS_TOKEN 必须是设备的访问令牌。 请求携带的参数如下,二个参数method和params {"method": …

PyCharm开发工具安装plugins插件

一. 简介 通过前面的学习,我们知道 python开发常用的一个开发工具(即IDE)是 PyCharm。 本文来简单介绍一下,PyCharm开发工具是如何安装 plugins插件的。其实与 vscode软件安装插件类似。 本文来学习 PyCharm开发工具安装一个中…

深入浅出MySQL-02-【MySQL支持的数据类型】

前言 环境: Windows11MySQL-8.0.35 1.数值类型 MySQL中的数值类型,如下: 整数类型字节最小值最大值TINYINT1有符号 -128无符号 0有符号 127无符号 255SMALLINT2有符号 -32768无符号 0有符号 32767无符号 65535MEDIUMINT3有符号 -8388608…