Java线程中断仅设置中断标志而非强制终止,线程是否响应由代码决定;阻塞方法抛出InterruptedException并清空中断状态,非阻塞逻辑需手动轮询isInterrupted()并妥善处理中断。
Java线程中断不是“杀掉线程”,而是设置中断标志
很多人以为 Thread.interrupt() 会强制终止线程,实际它只是给目标线程打上一个中断标记(isInterrupted() 返回 true),线程是否响应、何时响应、如何响应,完全由你自己代码决定。JVM 不会替你停止线程执行,也不会抛出异常——除非线程正在阻塞中。
常见错误现象:interrupt() 调用后线程还在跑;或调用后立即抛出 InterruptedException 却没处理,导致中断状态被清除又丢失。
- 阻塞方法(如
Thread.sleep()、Object.wait()、LockSupport.park())检测到中断时会主动抛出InterruptedException,并自动清除中断状态(即isInterrupted()变为false) - 非阻塞逻辑必须手动轮询
Thread.currentThread().isInterrupted()判断是否该退出 - 若捕获
InterruptedException后不重设中断状态(Thread.currentThread().interrupt()),上层调用者可能再也感知不到中断请求
在循环中正确响应中断的写法
多数业务线程都在 while 循环里干活,中断响应必须嵌入循环条件或内部判断,否则中断永远不生效。
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
try {
doWork();
Thread.sleep(1000); // 可能抛 InterruptedException
} catch (InterruptedException e) {
// 关键:重新设置中断状态,让外层 while 条件能退出
Thread.currentThread().interrupt();
break; // 或直接 return
}
}
注意:isInterrupted() 是实例方法,检查的是当前线程自身;不要用 someThread.isInterrupted() 去轮询别的线程——那只是快照,不可靠,也不符合协作式中断设计原则。
立即学习“Java免费学习笔记(深入)”;
- 避免用
Thread.interrupted()(静态方法)做循环条件,因为它会清空中断状态,导致下一次检查永远为false - 如果循环体耗时长且不包含阻塞调用,必须在关键位置插入
if (Thread.currentThread().isInterrupted()) break; - 不要在
catch (InterruptedException)中“吞掉”异常又不重置中断——这是最常被忽略的坑
ExecutorService.submit() 提交的任务怎么中断
通过 ExecutorService 提交的 Runnable 或 Callable,不能直接调用 thread.interrupt(),因为线程由线程池管理,你拿不到原始 Thread 引用。必须借助 Future.cancel(true)。
但要注意:Future.cancel(true) 的效果取决于任务是否响应中断: