"可中断"特指的是线程在某些特定的阻塞状态 下,能够响应来自其他线程的 interrupt() 调用。线程的生命周期有几个状态,中断信号只对其中一部分有效。
我们可以通过分析Java线程的状态(Thread.State)来清晰地回答这个问题:
Java线程的六大状态
- NEW (新建)
- RUNNABLE (可运行)
- BLOCKED (阻塞)
- WAITING (无限期等待)
- TIMED_WAITING (限期等待)
- TERMINATED (终止)
中断信号的有效范围
中断机制的本质是:当一个线程正在执行一个会抛出 InterruptedException 的方法时,调用其 interrupt() 方法才会立即触发异常。
下面是各个状态对中断的响应情况:
| 线程状态 | 是否可中断? | 说明与解释 |
|---|---|---|
| NEW | 否 | 线程还未启动,interrupt() 调用无效。中断状态不会被设置。 |
| TERMINATED | 否 | 线程已死亡,interrupt() 调用无效。 |
| RUNNABLE | 是,但行为不同 | 这是最关键的一点。 线程在运行中,没有阻塞。调用 interrupt() 不会 立即抛出异常或停止线程。它只是礼貌地设置了一个中断标志位 (isInterrupted() 将返回 true)。线程需要自己检查这个标志位来决定是否要停止工作。这是一种协作机制。 |
| BLOCKED | 否 | 线程在等待进入一个synchronized同步块 时处于此状态。在此状态下调用 interrupt() 无效 。它既不会抛出异常,也不会立即被中断。线程会一直保持BLOCKED状态,直到获取到锁 。一旦获取到锁,如果中断标志位已被设置,它可能会在随后调用可中断方法(如 wait())时立即抛出异常。 |
| WAITING | 是 | 线程因调用 Object.wait()、Thread.join()(无参)或 LockSupport.park() 而进入无限期等待。在这些状态下调用 interrupt() 会立即 唤醒线程,并抛出 InterruptedException。 |
| TIMED_WAITING | 是 | 线程因调用 Thread.sleep()、Object.wait(long timeout)、Thread.join(long timeout) 等方法而进入限期等待。在这些状态下调用 interrupt() 会立即 唤醒线程,并抛出 InterruptedException。 |
核心总结与记忆技巧
- 中断只对"等待"有效 :中断的核心目标是将线程从等待状态(WAITING/TIMED_WAITING)中唤醒 。对于
BLOCKED状态(等锁)和RUNNABLE状态(正常运行),它无法强行打断。 - 两种中断处理方式 :
- 被动处理(自动) :当线程在
WAITING或TIMED_WAITING状态时,中断会自动以异常形式通知线程。 - 主动处理(协作) :当线程在
RUNNABLE状态时,中断只是设置一个标志。线程必须主动、频繁地 检查这个标志(通过Thread.currentThread().isInterrupted())并自行处理,比如退出循环、返回结果等。
- 被动处理(自动) :当线程在
BLOCKED状态是个特例 :它不可中断。这是synchronized内置锁的一个局限性。相比之下,使用Lock.lockInterruptibly()方法可以在等待锁时响应中断,这是显式锁Lock的一个优势。
代码示例:RUNNABLE 状态下的中断
java
public class InterruptRunningThread {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 线程在RUNNABLE状态,运行一个长时间任务
while (!Thread.currentThread().isInterrupted()) { // 主动检查中断标志
System.out.println("Working hard...");
// 如果这里有一个非常耗时的计算,没有检查中断,线程就不会停止
}
System.out.println("线程收到中断信号,优雅地结束了。");
});
thread.start();
Thread.sleep(10); // 让子线程运行一会儿
thread.interrupt(); // 设置中断标志,但不会立即停止线程
}
}
结论: 一个线程只有在执行诸如 sleep(), wait(), join() 等声明了会抛出 InterruptedException 的方法时,才是"可中断"的。在其他状态下,中断仅仅是一个需要被监听的"建议"信号。