interrupt() 仅设置中断状态为 true,线程是否响应由自身逻辑决定;必须在循环中主动检查 isinterrupted(),捕获 interruptedexception 后立即重置中断状态,阻塞 i/o 需配合超时或关闭资源,推荐 volatile 标志位与 interrupt 双保险。

interrupt() 只是发信号,不是“关机键”
调用 thread.interrupt() 不会终止线程,它只做一件事:把目标线程的中断状态设为 true。线程是否响应、何时响应、怎么响应,完全由线程自己的逻辑决定。误以为“调用了就停了”,是绝大多数中断失效的根源。
必须在循环中主动检查中断状态
最常见错误是写了个 while (true) 却没检查中断,导致线程永远不退出。正确做法是在每次迭代开始或关键节点处,用 Thread.currentThread().isInterrupted() 判断:
- 用
isInterrupted()(非静态)——保留中断状态,适合多处检查 - 避免只用
Thread.interrupted()(静态)——它会清掉中断标志,后续再调用可能返回false,造成漏判 - 若循环里调用了可中断阻塞方法(如
Thread.sleep()、Object.wait()、BlockingQueue.take()),必须捕获InterruptedException - 捕获到
InterruptedException后,**必须立刻重置中断状态**:Thread.currentThread().interrupt(),否则上层代码再也收不到中断信号
阻塞 I/O 和第三方库常绕过中断机制
像老版本 java.net.Socket.getInputStream().read() 这类阻塞调用,不会响应 interrupt();某些数据库驱动、HTTP 客户端(如早期 OkHttp)也不保证中断传播。这类场景下:
- 优先换用支持中断的替代方案,例如
SocketChannel+Selector,或HttpClient的异步 API - 无法替换时,需配合超时(
setSoTimeout())+ 主动关闭底层资源(socket.close())来打破阻塞 - 不要依赖
shutdownNow()能“一键停止”——它只是对所有活跃线程调interrupt(),如果任务内部不响应,照样停不掉
volatile 标志位 + interrupt 双保险更可靠
纯靠中断容易被忽略(比如忘了捕获异常或漏查状态),尤其在复杂任务中。推荐组合使用:
- 声明一个
volatile boolean cancelled作为业务级取消标志 - 在
run()或任务主循环中,同时检查!cancelled && !Thread.currentThread().isInterrupted() - 外部调用方既调
thread.interrupt(),也设cancelled = true - 这样即使某处中断被吞或未处理,标志位仍能兜底;而中断又能及时唤醒阻塞中的线程
真正难的不是调用 interrupt(),而是确保每个可能阻塞、每个长循环、每个资源清理点,都对中断或取消标志有明确响应路径。漏掉任意一环,线程就可能卡死或泄漏。










