interrupt()、interrupted() 和 isInterrupted() 方法的区别是什么?
在 Java 的多线程编程中,interrupt()、interrupted() 和 isInterrupted() 都与线程中断机制有关。理解它们的区别,核心在于理解“中断状态”(Interrupt Status/Flag)这个概念。
简单来说,Java 的中断是一种协作机制,调用中断方法并不会立刻强行停止目标线程,而是给目标线程设置一个“中断标志”,目标线程需要自己去检查这个标志并决定如何处理。
以下是这三个方法的详细区别:
1. interrupt() —— “发出中断请求”
- 方法类型:实例方法 (
Thread类的非静态方法)。 - 作用对象:调用该方法的线程对象(例如
thread.interrupt()作用于thread线程)。 - 功能:设置线程的中断标志为
true。 - 特殊情况:如果目标线程正处于阻塞状态(例如调用了
Thread.sleep()、Object.wait()、Thread.join()等),调用interrupt()会让目标线程立刻抛出InterruptedException异常,并且中断标志会被立刻清除(重置为false)。
2. isInterrupted() —— “查看中断状态(只看不改)”
- 方法类型:实例方法 (
Thread类的非静态方法)。 - 作用对象:调用该方法的线程对象(例如
thread.isInterrupted()检查thread线程的状态)。 - 功能:返回线程当前的中断状态(
true或false)。 - 是否清除标志:否。无论调用多少次,它只是读取状态,绝不改变中断标志的值。
3. interrupted() —— “查看并清除中断状态(看完就删)”
- 方法类型:静态方法 (
Thread.interrupted())。 - 作用对象:当前正在执行此代码的线程(即
Thread.currentThread())。 - 功能:返回当前线程的中断状态,并且将中断标志位清除(重置为
false)。 - 是否清除标志:是。如果连续调用两次该方法,第二次一定会返回
false(除非在两次调用之间线程再次被中断)。
📝 核心对比总结表
| 方法名 | 方法类型 | 作用于哪个线程 | 主要功能 | 是否清除中断标志位? |
|---|---|---|---|---|
interrupt() |
实例方法 | 具体的线程对象 | 打断该线程(设置标志为 true) | 否(但抛出 InterruptedException 时会被底层清除) |
isInterrupted() |
实例方法 | 具体的线程对象 | 判断该线程是否被中断 | 否 |
interrupted() |
静态方法 | 当前运行的线程 | 判断当前线程是否被中断 | 是(检查后立刻设为 false) |
💻 代码示例与场景分析
场景 1:isInterrupted() 和 interrupted() 的对比
java
public class InterruptDemo {
public static void main(String[] args) {
Thread.currentThread().interrupt(); // 中断主线程自己
// 此时主线程的中断标志为 true
// isInterrupted() 只读取,不清除
System.out.println(Thread.currentThread().isInterrupted()); // 输出 true
System.out.println(Thread.currentThread().isInterrupted()); // 输出 true
// interrupted() 读取并清除
System.out.println(Thread.interrupted()); // 输出 true (读取到了中断状态,随后将其清除为 false)
System.out.println(Thread.interrupted()); // 输出 false (状态已经被上一步清除了)
}
}
场景 2:抛出 InterruptedException 时的陷阱(非常重要)
当你捕获了 InterruptedException 后,线程的中断标志会被底层自动清除(变成 false)。如果你不重新中断,上层代码将无法感知到这个线程曾经被中断过。
java
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
// 模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
// 注意:此时发生异常,中断标志位已经被自动清除了(变成了 false)
// 【正确做法】:重新设置中断标志,让外层的 while 循环能感知到中断并退出
Thread.currentThread().interrupt();
System.out.println("线程在睡眠时被中断,准备退出");
}
}
});
thread.start();
Thread.sleep(500); // 让子线程先飞一会儿
thread.interrupt(); // 中断子线程
💡 总结口诀
interrupt():去打断别人(或自己)。isInterrupted():悄悄看别人(或自己)有没有被打断。interrupted():看自己有没有被打断,看完顺手把痕迹抹掉。