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();
}

通过 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();
}

通过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();
}

二、中断的相关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) :判断线程是否已经中断,不会清除状态;
    在这里插入图片描述
    今儿就先到这里啦,小伟查缺补漏去咯~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值