• Java线程中断机制



    鉴于最近找实习并发编程问的挺多的,闲暇之际特来整理一下:

    首先

    一个线程不应该由其他线程来强制中断或停止,而是 应该由线程自己自行停止,自己来决定自己的命运。

    所以,Thread.stop,Thread.suspend,Thread.resume 都已经废弃了。

    其次

    在 Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。

    因此,Java提供了一种用于停止线程的协商机制——中断,即中断标识协商机制。

    中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。
    若要中断一个线程,你需要手动调用该线程的 interrupt方法,该方法也仅仅是将线程对象的中断标识设成 true

    接着你需要自己写代码不断地检测当前线程的标识位,如果为 true,表示别的线程请求这条线程中断,此时究竟做什么需要你自己写代码实现。

    每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该表示位为true表示中断,为false表示未中断;通过调用线程对象的 interrupt方法将线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

    即:中断只是一种协商机制,修改中断标识位仅此而已,不是立刻stop打断。


    一、实现中断运行中的线程

    比如说老师总会问 如何停止中断运行中的线程?那么这里小伟为大家整理主要有以下三种方式:

    通过volatile实现线程中断停止

    private static void m1_volatile() {
        new Thread(()->{
            while (true) {
                if (isStop) {
                    System.out.println(Thread.currentThread().getName()+"\t isStop 被修改为true,程序停止");
                    break;
                }
                System.out.println("t1 -----hello volatile");
            }
        },"t1").start();
    
        // 暂停20毫秒
        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            isStop = true;
        },"t2").start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    通过 AtomicBoolean实现线程中断停止

    AtomicBoolean(原子布尔型)

    private static void m2_atomicBoolean() {
        new Thread(()->{
            while (true) {
                if (atomicBoolean.get()) {
                    System.out.println(Thread.currentThread().getName()+"\t atomicBoolean 被修改为true,程序停止");
                    break;
                }
                System.out.println("t1 -----hello atomicBoolean");
            }
        },"t1").start();
    
        // 暂停20毫秒
        try {
            TimeUnit.MILLISECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            atomicBoolean.set(true);
        },"t2").start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    通过Thread类自带的中断Api实例方法实现

    在需要中断的线程中 不断监听中断状态,一旦发生中断,就执行相应的中断处理业务逻辑stop线程

    private static void m3_ThreadApi() {
        Thread t1 = new Thread(()->{
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println(Thread.currentThread().getName() + "\t isInterrupted()被修改为true,程序停止");
                    break;
                }
                System.out.println("t1 ----hello interrupt api");
            }
        },"t1");
        t1.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            t1.interrupt();
        },"t2").start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二、中断的相关API方法

    接下来我们对 Thread类自带的中断Api实例方法进行探索吧~

    再次来探讨一下如何停止线程吧?

    • run 方法执行完成,自然终止;
    • stop() 方法、suspend()、resume() 都是过期作废方法,使用它们结果不可预期;

    大多数停止一个线程的操作使用 Thread.interrupted() 等于说给线程打一个停止的标记,此方法不会去终止一个正在运行的线程,需要加入一个判断才能可以完成线程的终止;

    • interrupted :判断当前线程是否已经中断,清除状态;
    • isInterrupted :判断线程是否已经中断,不会清除状态;

    通过Api文档对以上三个方法做个简单的介绍吧:
    在这里插入图片描述

    • public void interrupt() :中断这个线程

      源码注解:Just to set the interrupt flag

      实例方法 interrupt() 仅仅是设置线程的中断状态为 true,发起一个协商而不会立刻停止线程。

    • public static boolean interrupted() :判断当前线程是否已经中断,清除状态;

      这个方法做了两件事:

      1. 返回当前线程的中断状态,测试当前线程是否已被中断
      2. 将当前线程的中断状态清零并重新设为false,清除线程的中断状态
    • public boolean isInterrupted():判断当前线程是否被中断(通过检查中断标志位)

    源码探究时刻~

    让我们来看看interrupt()方法的源码,发现实则是调用了本地方法 interrupt0(),Just to set the interrupt flag,仅是将该线程的中断标志设置为true。所以,interrupt()方法并不能真正的中断线程,需要被调用的线程自己进行配合才行。
    在这里插入图片描述
    当然,如果线程处于被阻塞状态(例如处于 sleep、wait、join 等状态),在别的线程中调用当前线程对象 interrupt()方法,那么线程将立即退出被阻塞状态,并清除它的中断状态,并抛出一个 InterruptedException异常。此时线程的中断标志位为false,中断不打断。解决方法是:在catch()代码块中调用 interrupt()方法。

    再来看看 interrupted()isInterrupted() 方法的源码,发现两个方法底层都是调用了本地方法isInterrupted() ,该方法注解内容为:测试某个线程是否中断。中断状态是否重置取决于传递的ClearInterrupted的值。

    • interrupted() ——> isInterrupted(true):判断当前线程是否已经中断,清除状态;
    • isInterrupted ——> isInterrupted(false) :判断线程是否已经中断,不会清除状态;
      在这里插入图片描述
      今儿就先到这里啦,小伟查缺补漏去咯~
  • 相关阅读:
    使用新的 NVIDIA Isaac Foundation 模型和工作流程创建、设计和部署机器人应用程序
    如何更改文件类型?4个方法,轻松操作!
    JavaScript实现单词首字母大写的方法总汇
    js基础知识整理之 —— Date和定时器
    【图像分类】MMPretrain训练ImageNet格式自定义数据集
    VSCode配置 C/C++ 环境
    AI DevOps | ChatGPT 与研发效能、效率提升(中)
    Windows家庭版开启远程桌面的方法
    单点登录的三种方式
    分享面试阿里、京东、网易等大厂后的面经及面试心得—远程面试
  • 原文地址:https://blog.csdn.net/m0_49183244/article/details/125473764