浅谈线程中断

本文介绍了Java线程中断的概念,强调中断是一种协作机制,不能直接终止线程,而是通过改变中断状态并配合中断异常来协作处理。文章讨论了如何响应中断,包括`interrupt()`、`isInterrupted()`和`interrupted()`方法的使用,并通过实例展示了线程在阻塞状态时被中断会抛出`InterruptedException`,从而提前解除阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

        在多线程中,如果我们由于一些特殊的原因,想让已经进入阻塞的线程提前解除阻塞,进而进行执行后面的代码,那么线程中断这个方法,会让我们很轻松的达到这个目的。

中断原理

        Java 中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。

        即在线程A中调用线程B的interrupt(),会使线程B的中断状态位置为true,线程B可以选择在合适的时候处理这个请求,也可以完全忽视这个请求。

java.lang.Thread 类提供了几个方法来操作这个中断状态,这些方法包括:

public boolean isInterrupted(){
	//...
}

public void interrupt() {
	//...
}

public static boolean interrupted() {
	//...
}

        其中
                interrupt():将线程的中断状态位设置为true。仅仅这一个功能而已。

                isInterrupted():判断线程是否已经中断,若已经中断返回true,否则返回false。仅仅用来判断线程是否已经被中断。

                interrupted():判断当前线程是否被中断,现成的中断状态由该方法清除。若连续调用两次该方法,则第二次调用将返回false。

如何响应中断?

        谈一谈我的理解,我们上面提到过,当一个线程进入阻塞状态时,由于一些特殊的原因,我们必须让这个阻塞提前解除,进而让该进程继续往下执行任务,那我们如何提前解除阻塞呢?线程中断就是一个好的方法。

        当一个线程A进入阻塞时,如果其他线程调用了A的interrupt()时,此时线程A的中断状态位为变为true。并且会抛出一个InterruptException异常。我们可以通过捕获这个异常,然后进行一些相关的操作,下面是一个例子:

        线程A始终在睡眠状态,线程B中调用了线程A的interrput():

class MyThread extends Thread{
    public void run(){
        try {
            System.out.println("线程A在睡眠之前的中断状态位:" + Thread.currentThread().isInterrupted());
            System.out.println("线程A在睡眠");
            TimeUnit.SECONDS.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println("阻塞解除后,线程A正常做其他的事情...");
            System.out.println("抛出异常后线程A的中断状态位:" + Thread.currentThread().isInterrupted());
        }
    }
}

class MyThread2 extends Thread{
    private MyThread m1;
    public MyThread2(MyThread t){
       m1 = t;
    }
    public void run(){
        System.out.println("线程A睡眠时,线程A的中断状态位:" + m1.isInterrupted());
        m1.interrupt();
//        m1.interrupted();
        System.out.println("线程B中调用了线程A的interrupt(),线程A的中断状态位:" + m1.isInterrupted());
        for (int i = 0; i < 3; i++) {
            System.out.print(Thread.currentThread().getName() + ":" + i+ ",   ");
        }
        System.out.println();
    }
}

public class TestDemo2 {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        MyThread2 m2 = new MyThread2(m1);
        m2.setName("线程B");
        m1.start();
        m2.start();
    }

在这里插入图片描述
        我们可以根据运行结果,先判断出线程A和线程B哪个线程在执行。

        很明显,通过第一行、第二行运行结果,线程A先执行,当执行到sleep()方法时,进入睡眠,让出cpu资源,此时线程B开始执行,线程B一开始就将线程A的中断状态位置为true,注意此时线程A已经是睡眠状态了,这个时候,线程A就会抛出一个Interruption异常,当线程B执行完自己的事情后,由于线程A抛出了异常,此时指向catch{}代码块里的程序,也就是我们看到运行结果的倒数两行。这个时候我们发现,线程A捕获了异常后,并没有结束运行,而是执行了catch{}中的代码,并且将A的中断状态位重新置为false。

        所以,通过上面的例子我们能看出

                ① 当一个线程处于阻塞状态时,如果设置该线程的中断状态位为true,则会抛出InterruptedException
                ② 抛出InterruptedException异常后,会擦除线程的中断状态位。

        接着我们演示一下,interrupted()方法,到底能不能擦除中断状态位?

        我们只需要修改上述代码即可:

class MyThread2 extends Thread{
    private MyThread m1;
    public MyThread2(MyThread t){
       m1 = t;
    }
    public void run(){
        System.out.println("线程A睡眠时,线程A的中断状态位:" + m1.isInterrupted());
        m1.interrupt();
                System.out.println("线程B中调用了线程A的interrupt(),线程A的中断状态位:" + m1.isInterrupted());
		boolean flag = m1.interrupted();
		        System.out.println("调用interrupted()方法后,线程A的中断状态位:" + flag);
        for (int i = 0; i < 3; i++) {
            System.out.print(Thread.currentThread().getName() + ":" + i+ ",   ");
        }
        System.out.println();
    }
}

在这里插入图片描述
        我们可以看到,interrupted()是可以清除中断状态位的。

总结

        中断机制的核心在于中断状态位InterruptedException异常。

        设置一个中断状态:interrupt()

        擦除一个中断状态:interrupted()

        如下的方法能够使线程进入阻塞状态,调用interrupt()可以打断阻塞。因此这些方法被称为:可中断方法
                        Object.wait()/wait(long mills)
                        Thread.sleep(long)/ TimUnit.XXX.sleep(long)
                        Thread.join()/Thread(long mills)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值