Thread 之 interrupt、isInterrupted、interrupted 方法

发布时间 2024-01-10 17:33:55作者: 变体精灵

interrupt(): 打断 sleep、wait、join 的线程会抛出 InterruptedException 异常并清除打断标记,如果打断正在运行的线程、park 的线程则会重新设置打断标记
isInterrupted(): 不会清除打断标记
interrupted(): 会清除打断标记

一、调用 interrupt() 方法中断正在运行的线程

@Slf4j
public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {

            }
        });
        t1.start();

        // 先让 t1 线程运行
        TimeUnit.SECONDS.sleep(1);
        // isInterrupted() 可以获取到线程的打断标记,如果线程被打断,则打断标记为 true,并且该方法不会清除打断标记
        log.info("before interrupt status >>> {}", t1.isInterrupted());
        // 打断正在运行的线程/park 状态的线程会重新设置打断标记,打断 sleep、join、wait 状态的线程会抛出 InterruptedException 异常,并且会清除打断标记
        t1.interrupt();
        log.info("after interrupt status >>> {}", t1.isInterrupted());
    }
}

中断正在运行的线程时,线程的中断状态变成 true,线程正常运行,并不会停止下来

调用 interrupt() 方法中断处于 sleep、wait、join 状态的线程

@Slf4j
public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                // t1 线程休眠 1000s
                TimeUnit.SECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.info("{} 线程被打断了", Thread.currentThread().getName());
            }
        }, "t1");

        t1.start();

        // 主线程休眠 2s,让 t1 线程有足够的时间进入 sleep 状态
        TimeUnit.SECONDS.sleep(2);
        log.info("before interrupt status >>> {}", t1.isInterrupted());
        t1.interrupt();
        // 主线程休眠 2s,让 t1 线程有足够的时间进行 interrupt 操作
        TimeUnit.SECONDS.sleep(2);
        log.info("after interrupt status >>> {}", t1.isInterrupted());
    }
}

中断处于 sleep、join、wait 状态的线程会抛出异常,并且会将中断状态重置为 false

 中断时线程的状态  中断后线程的中断标记 中断后线程运行情况 
 正常运行的线程  false -> true  线程正常运行
 sleep、wait、join 状态的线程  false -> true -> false  线程抛出异常,中止运行

然后再看一下 isInterrupted 和 interrupted 的区别

先看一下 isInterrupted() 方法源码

public boolean isInterrupted() {
	// ClearInterrupted 参数的含义是否清除打断标记 
	// false 代表不清除,打断之后 false -> true
	// true 代表清除,打断之后会重置打断标记 false -> true -> false
	return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);

接着再看一下 interrupted() 方法源码

public static boolean interrupted() {
	return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);

从上面的源码中可以看出 isInterrupted() 方法和 interrupted() 方法实际上底层都是调用 private native boolean isInterrupted(boolean ClearInterrupted) 方法,唯一的区别就是传递的参数,一个是 false,一个是 true,也就是一个不会清除打断标记,另外一个会清除打断标记

线程调用 interrupt() 方法并不会真正中断线程,而是让线程具有响应中断的能力,如果你可以在 main 线程中随意的去停止 t1 线程,而 t1 线程却毫无察觉,这不是一件很可怕的事情吗,真正中断的操作应该由 t1 线程去决定,而不是 main 线程,常用的做法是在 t1 线程中根据打断标记去执行不同的逻辑