JAVA线程中断

1、线程中断

在Java中,线程中断是一种重要的线程间通信机制,用于通知线程应该停止当前正在执行的任务。以往,一些开发人员可能会使用 Thread.stop()、Thread.suspend() 和 Thread.resume() 这些方法来尝试停止线程,然而这些方法自Java 2平台标准版 (J2SE) 1.2 版本起就已经被标记为过时。因此,在开发中,我们应该以更安全的方式来使线程停止,例如通过改变一个标志位来让线程自主停止运行。
所以,我们推荐使用 interrupt() 方法来通知线程应该停止执行。通过调用 interrupt() 方法,可以设置线程的中断状态,然后在适当的时候检查这个中断状态并做出相应的处理,让线程安全地停止执行。这种做法既符合最佳实践,又能确保线程的安全性和可靠性。

2、相关API

interrupt方法()是通知指定线程中断,并且将该线程的中断位变为true,并不会将该线程直接中断。
isInterrupted方法()是返回指定线程的中断位标志。
interrupted方法()是返回指定线程的当前中断位标志,并且会将中断位变为flase。

3、如何使用中断标识停止线程

3.1正常运行状态下调用interrupt()

public class Demo {

    public static void main(String[] args) {
        Thread a = new Thread(() -> {
            System.out.println("进入线程A");

            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("中断标志位被置为true,线程中断。。");
                    break;
                }
                System.out.println("线程A中断标志位为:"+Thread.currentThread().isInterrupted());
            }

        }, "a");
        a.start();

        new Thread(()->{
            System.out.println("进入线程B");
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            a.interrupt();
            System.out.println("a.interrupt()调用之后,线程的中断标识值: "+a.isInterrupted()); //isInterrupted返回a线程的中断位标志
        },"b").start();
    }
}

上列代码中,线程A通过一个无限循环来执行任务。在每次循环中,它检查自身的中断状态(通过isInterrupted()),如果中断标志位被置为true,就输出相应的信息并跳出循环,以实现线程的停止。所以我们得出结论:
在A线程正常运行状态下,B线程调用 a.interrupt()方法会使得A线程的中断标志位由默认值false变为true,但此时A线程并不会中断,而是需要A线程去配合中断。

在这里插入图片描述
但如果我们在A线程阻塞状态(sleep、wait、join等)下调用interrupt()方法会发生什么?

3.2阻塞状态下调用interrupt()

public class Demo {
    public static void main(String[] args) {
        Thread a = new Thread(() -> {
            System.out.println("进入线程A");
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("中断标志位被置为true,线程中断。。");
                    break;
                }
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程A中断标志位为:"+Thread.currentThread().isInterrupted());
            }
        }, "a");
        a.start();
        new Thread(()->{
            System.out.println("进入线程B");
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            a.interrupt();
            System.out.println("线程B调用a.interrupt()已完成");
        },"b").start();
    }
}

上列代码我们在A线程的循环体中加入了睡眠3秒的操作,此时线程B调用 a.interrupt()。运行结果如下:
在这里插入图片描述
从上图我们发现两点:
1、打印出了java.lang.InterruptedException: sleep interrupted
2、线程B调用a.interrupt()后为什么线程A的中断标志位还是false?

我们先看第一个问题,这个问题interrupt()方法源码可以看见以下注释:

当线程在调用 Object 类的 wait()、wait(long)、wait(long, int) 方法,或者调用 Thread 类的 join()、join(long)、join(long, int)、sleep(long)、sleep(long, int) 方法时被阻塞,那么它的中断状态将会被清除,并且它会收到一个 InterruptedException。

在这里插入图片描述
所以我们得到第一个结论,线程如果在阻塞状态时调用**interrupt()**方法我们会收到一个 InterruptedException

接下来我们看第二个问题,为什么线程B调用a.interrupt()为后什么线程A的中断标志位还是false?

在这里插入图片描述
我们从sleep方法中可以看见,抛出InterruptedException时,线程的中断标志位会被清除(变为false)。此时我们需要在catch方法中重新调用interrupt()方法将线程的中断标志位置为true。

Thread.currentThread().interrupt();

4、总结

  • 在java中,我们想要可以使用interrupt()方法来将目标线程的中断标志位置为true,但此方法不会立即停止线程运行,需要目标线程配合。
  • 在目标线程正常运行状态时,调用interrupt()可以正常将目标线程的中断标志位置为true。在目标线程阻塞状态时,调用interrupt()会出现异常并使得目标线程的中断标识位重新变为false。
  • 我们也可以使用volatile变量或者原子类实现线程中断。
  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值