并发编程之interrupt方法的详细解析

3.9 interrupt方法详解

Interrupt说明

interrupt的本质是将线程的打断标记设为true,并调用线程的三个parker对象(C++实现级别)unpark该线程。

基于以上本质,有如下说明:

  • 打断线程不等于中断线程,有以下两种情况:

    • 打断正在运行中的线程并不会影响线程的运行,但如果线程监测到了打断标记为true,可以自行决定后续处理。

    • 打断阻塞中的线程会让此线程产生一个InterruptedException异常,结束线程的运行。但如果该异常被线程捕获住,该线程依然可以自行决定后续处理(终止运行,继续运行,做一些善后工作等等)

打断 sleep,wait,join 的线程

这几个方法都会让线程进入阻塞状态

打断 sleep 的线程, 会清空打断状态,以 sleep 为例

private static void test1() throws InterruptedException {
    Thread t1 = new Thread(()->{
        sleep(1);
    }, "t1");
    t1.start();
    sleep(0.5);
    t1.interrupt();
    log.debug(" 打断状态: {}", t1.isInterrupted());
}

输出

java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at java.lang.Thread.sleep(Thread.java:340)
 at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
 at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8)
 at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59)
 at java.lang.Thread.run(Thread.java:745)
21:18:10.374 [main] c.TestInterrupt - 打断状态: false

打断正常运行的线程

打断正常运行的线程, 不会清空打断状态

private static void test2() throws InterruptedException {
    Thread t2 = new Thread(()->{
        while(true) {
            Thread current = Thread.currentThread();
            boolean interrupted = current.isInterrupted();
            if(interrupted) {
                log.debug(" 打断状态: {}", interrupted);
                break;
            }
        }
    }, "t2");
    t2.start();
    sleep(0.5);
    t2.interrupt();
}

输出

20:57:37.964 [t2] c.TestInterrupt - 打断状态: true

* 模式之两阶段终止

Two Phase Termination 在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。

错误思路
  • 使用线程对象的 stop() 方法停止线程

    • stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁, 其它线程将永远无法获取锁

  • 使用 System.exit(int) 方法停止线程

    • 目的仅是停止一个线程,但这种做法会让整个程序都停止

两阶段终止模式

利用 isInterrupted

interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行

class TPTInterrupt {
    private Thread thread;
    public void start(){
        thread = new Thread(() -> {
            while(true) {
                Thread current = Thread.currentThread();
                if(current.isInterrupted()) {
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    log.debug("将结果保存");
                } catch (InterruptedException e) {
                    current.interrupt();
                }
                // 执行监控操作 
            }
        },"监控线程");
        thread.start();
    }
    public void stop() {
        thread.interrupt();
    }
}

调用

TPTInterrupt t = new TPTInterrupt();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();

结果

11:49:42.915 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:43.919 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:44.919 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:45.413 c.TestTwoPhaseTermination [main] - stop 
11:49:45.413 c.TwoPhaseTermination [监控线程] - 料理后事
利用停止标记
// 停止标记用 volatile 是为了保证该变量在多个线程之间的可见性
// 我们的例子中,即主线程把它修改为 true 对 t1 线程可见
class TPTVolatile {
    private Thread thread;
    private volatile boolean stop = false;
    public void start(){
        thread = new Thread(() -> {
            while(true) {
                Thread current = Thread.currentThread();
                if(stop) {
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    log.debug("将结果保存");
                } catch (InterruptedException e) {
                }
                // 执行监控操作
            }
        },"监控线程");
        thread.start();
    }
    public void stop() {
        stop = true;
        thread.interrupt();
    }
}

调用

TPTVolatile t = new TPTVolatile();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();

结果

11:54:52.003 c.TPTVolatile [监控线程] - 将结果保存
11:54:53.006 c.TPTVolatile [监控线程] - 将结果保存
11:54:54.007 c.TPTVolatile [监控线程] - 将结果保存
11:54:54.502 c.TestTwoPhaseTermination [main] - stop 
11:54:54.502 c.TPTVolatile [监控线程] - 料理后事

打断 park 线程

打断 park 线程, 不会清空打断状态

private static void test3() throws InterruptedException {
    Thread t1 = new Thread(() -> {
        log.debug("park...");
        LockSupport.park();
        log.debug("unpark...");
        log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
    }, "t1");
    t1.start();
    sleep(0.5);
    t1.interrupt();
}

输出

21:11:52.795 [t1] c.TestInterrupt - park... 
21:11:53.295 [t1] c.TestInterrupt - unpark... 
21:11:53.295 [t1] c.TestInterrupt - 打断状态:true 

如果打断标记已经是 true, 则 park 会失效

private static void test4() {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 5; i++) {
            log.debug("park...");
            LockSupport.park();
            log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
        }
    });
    t1.start();
    sleep(1);
    t1.interrupt();
}

输出

21:13:48.783 [Thread-0] c.TestInterrupt - park... 
21:13:49.809 [Thread-0] c.TestInterrupt - 打断状态:true 
21:13:49.812 [Thread-0] c.TestInterrupt - park... 
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true 
21:13:49.813 [Thread-0] c.TestInterrupt - park... 
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true 
21:13:49.813 [Thread-0] c.TestInterrupt - park... 
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true 
21:13:49.813 [Thread-0] c.TestInterrupt - park... 
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true 

提示

可以使用 Thread.interrupted() 清除打断状态

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

hcia静态实验

题目&#xff1a; 要求&#xff1a; 1、R6为isp&#xff0c;接口ip均为公有地址&#xff0c;该设备只能配置ip地址&#xff0c;之后不能再对其进行任何其他配置 2、r1到r5为局域网&#xff0c;私有ip地址为192.168.1.0 24&#xff0c;合理分配 3、r1,r2,r4各有两个环回地址&am…

python基础——语句

一、条件语句 就是 if else 语句 &#xff01; 代表不等于 代表等于if 关键字&#xff0c;判断语句&#xff0c;有“如果”的意思&#xff0c;后面跟上判断语句else 常和“if” 连用&#xff0c;有“否则”的意思&#xff0c;后面直接跟上冒号 …

探秘空投女巫:区块链世界的神秘现象

在区块链世界中&#xff0c;充满了各种新奇的名词和概念&#xff0c;其中一个引人注目的现象就是“空投女巫”。这个神秘的名字让人不禁好奇&#xff0c;究竟是什么&#xff1f; 什么是空投女巫&#xff1f; 空投女巫是指那些在区块链项目中频繁参与空投活动&#xff0c;并且…

[Netty实践] 简单聊天实现(四):Server集群改造

目录 一、介绍 二、解决方案 三、server端改造 五、客户端改造 四、测试 五、拓展 一、介绍 本章是拓展内容&#xff0c;主要实现的是Server集群。 当系统的用户多了之后&#xff0c;单机Server资源有限&#xff0c;无法提供socket连接时&#xff0c;我们需要部署Serve…

[Linux]多线程(在Linux中的轻量级进程(LWP),怎么使用线程(接口))

目录 一、在Linux中的轻量级进程&#xff08;LWP&#xff09; 二、多线程的接口 1.创建线程&#xff08;pthread_create&#xff09; 2.线程ID&#xff08;pthread_self&#xff09; 3.线程终止 终止某个线程而不终止整个进程的三种方法&#xff1a; return pthread_…

Python Windows系统 虚拟环境使用

目录 1、安装 2、激活 3、停止 1、安装 1&#xff09;为项目新建一个目录&#xff08;比如&#xff1a;目录命名为learning_log&#xff09; 2&#xff09;在终端中切换到这个目录 3&#xff09;执行命令&#xff1a;python -m venv ll_env&#xff0c;即可创建一个名为ll…

基于ssm的医院住院管理系统论文

摘 要 随着时代的发展&#xff0c;医疗设备愈来愈完善&#xff0c;医院也变成人们生活中必不可少的场所。如今&#xff0c;已经2021年了&#xff0c;虽然医院的数量和设备愈加完善&#xff0c;但是老龄人口也越来越多。在如此大的人口压力下&#xff0c;医院住院就变成了一个问…

YOLOv2学习

YOLOv2学习 引入 Anchor boxes摘要数据集组合方法&#xff08;Dataset Combination Method&#xff09;联合训练算法&#xff08;Joint Training Algorithm&#xff09;改进Batch NormalizationHigh Resolution Classifier分类器预训练分辨率调整**Convolutional With Anchor B…

鸿蒙Harmony应用开发—ArkTS-全局UI方法(警告弹窗)

显示警告弹窗组件&#xff0c;可设置文本内容与响应回调。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 本模块功能依赖UI的执行上下文&#xff0c;不可在UI上下文不明确的地方使用&#xff0c;参见UI…

云手机为电商提供五大出海优势

出海电商行业中&#xff0c;各大电商平台的账号安全是每一个电商运营者的重中之重&#xff0c;账号安全是第一生产力&#xff0c;也是店铺运营的基础。因此多平台多账号的防关联管理工具成了所有电商大卖家的必备工具。云手机最核心的优势就是账户安全体系&#xff0c;本文将对…

网络仿真3-NS2协议修改和移植

Ns2实现原理 OTcl与C关联 执行路径&#xff1a;Tcl->Otcl->C 返回路径&#xff1a;C->Otcl->Tcl NS2协议修改和移植 NS2中的各种网络协议在底层通过C实现&#xff0c;在网络仿真过程中最终通过调用底层C代码实现网络行为、算法、功能等各种仿真 NS2协议修改&…

vue3+threejs新手从零开发卡牌游戏(三):尝试在场景中绘制一张卡牌

首先我们思考下&#xff0c;一张最简单的卡牌有哪些东西构成&#xff1a;卡牌样式和卡牌数据。一张卡牌有正面和背面&#xff0c;有名称、属性、种族、攻击力等数据&#xff0c;我们先不考虑数据&#xff0c;先尝试在场景中绘制一张卡牌出来。 一、寻找卡牌素材 为了简单我直…

2024第二届经济管理、贸易与信息技术创新国际会议(ICEMITI2024)

2024第二届经济管理、贸易与信息技术创新国际会议&#xff08;ICEMITI2024&#xff09; 会议简介 2024第二届经济管理、贸易与信息技术创新国际会议&#xff08;ICEMITI2024&#xff09;将在中国郑州举行。这是一个重要的学术会议&#xff0c;旨在讨论当前经济管理、贸易和信…

python中类的导入与使用

1、类的介绍 与C中面向对象思想类似&#xff0c;有时候为了方便&#xff0c;需要专门创建一个类&#xff0c;将相关的函数全部写入到该类中&#xff0c;方便后续创建对象&#xff0c;再使用类中函数。那么如何创建完类&#xff0c;在其他文件中使用类中函数&#xff0c;这是这篇…

Design Script 官方案例解析3:函数

在本练习中,我们将创建一个通用定义,该定义将通过输入的点列表创建球体。这些球体的半径由每个点的 Z 特性驱动。 首先从 0 到 100 的十个值范围开始。将这些值插入 Point.ByCoordinates 节点,以创建对角线。 创建代码块,然后使用一行代码引入定义:def sphereByZ(inputPt)…

“找不到msvcr100.dll”或“msvcr100.dll丢失”的多种解决方法分享

当计算机系统中msvcr100.dll文件发生丢失时&#xff0c;导致某些应用程序无法正常运行。msvcr100.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;对于许多基于Windows操作系统的应用程序正常运行至关重要。小编将介绍5种解决msvcr100.dll丢失问题的方法…

LeetCode-热题100:17.电话号码的字母组合

题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a; digits “23” 输出&a…

云打印和无线打印有什么区别?

近段时间&#xff0c;云打印的概念越来越火热&#xff0c;而与此同时&#xff0c;无线打印也逐渐被大家所接受。那么云打印和无线打印有什么区别&#xff1f;今天带大家来了解一下。 云打印和无线打印有什么区别&#xff1f; 想要了解云打印和无线打印的区别&#xff0c;首先我…

org.springframework.boot:type=Admin,name=SpringApplication异常

javax.management.InstanceNotFoundException: org.springframework.boot:typeAdmin,nameSpringApplication 问题描述&#xff1a; IDEA 新建 SpringBoot 项目&#xff0c;启动时后台报错&#xff1a; javax.management.InstanceNotFoundException: org.springframework.boot…

图论必备:Dijkstra、Floyd与Bellman-Ford算法在最短路径问题中的应用

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;アンビバレント—Uru 0:24━━━━━━️&#x1f49f;──────── 4:02 &#x1f504; ◀️ ⏸ ▶️ ☰ …