InterruptedException 是线程协作信号而非错误,捕获后必须调用 Thread.currentThread().interrupt() 恢复中断状态,否则中断语义失效;阻塞方法响应中断,计算循环需手动轮询 isInterrupted()。
Java 中 InterruptedException 不代表程序出错了,而是 JVM 在调用 Thread.sleep()、Object.wait()、BlockingQueue.take() 等阻塞方法时,检测到当前线程被其他线程调用了 interrupt(),于是主动抛出该异常来“唤醒”它。忽略或吞掉这个异常,等于屏蔽了中断请求,线程将无法被及时停止,破坏中断语义。
标准做法是:在 catch (InterruptedException e) 块中,立即调用 Thread.currentThread().interrupt() 恢复中断标志位。否则上层调用者(比如框架或容器)将收不到中断信号,导致超时控制、任务取消等机制失效。
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
doWork();
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // ✅ 关键:恢复中断
break;
}
}
}
e.printStackTrace() 或空 catch —— 这是最常见误用InterruptedException(如实现了 Runnable.run()),必须恢复中断,不能转成 RuntimeException 包装后扔出去(除非你明确知道上层会处理)调用 thread.interrupt() 只有在目标线程正阻塞于可中断方法(如 sleep、wait、join、LockSupport.park())时才会立即触发 InterruptedException;若线程正在执行普通代码(比如密集计算),则只会设置中断标志位 isInterrupted() == true,需手动轮询检查。
if (Thread.currentThread().isInterrupted()) break;
Thread.interrupted() 是静态方法,会清除中断状态;isInterrupted() 是实例方法,不改变状态 —— 一般优先用后者ExecutorService.shutdownNow() 会尝试对所有运行中的任务线程调用 interrupt(),但效果取决于任务自身是否响应中断不是所有阻塞操作都响应中断。例如:
InputStream.read() 在 socke
InterruptibleChannel,如 SocketChannel)ReentrantLock.lock() 不响应中断;必须用 lockInterruptibly()
CountDownLatch.await()、Semaphore.acquire() 都响应中断@SneakyThrows 会自动吞掉 InterruptedException,极易引发中断丢失 —— 生产环境禁用关键点在于:中断安全不是“加个 try-catch 就完事”,而是整个执行路径上每一处阻塞点都要确认是否可中断、是否恢复了中断状态、是否在非阻塞段做了轮询。漏掉任意一环,中断就可能静默失效。