interrupt()仅设置中断标志或唤醒阻塞线程,具体响应由jvm根据线程状态决定:runnable时只设标志;sleep/wait/join时抛interruptedexception并清标志;nio阻塞抛closedbyinterruptexception;selector.select()仅唤醒并设标志;忙循环需手动检查isinterrupted()。

直接看 JDK 源码分析 Thread.interrupt() 的响应机制,关键不是“找一行代码定生死”,而是理解三层协作逻辑:JVM 层设置标志、Java 层方法契约、线程状态驱动行为差异。核心入口在 Thread.java 和底层 native 实现,但真正决定“怎么响”的,是线程当前所处的执行状态。
interrupt() 方法本身只做一件事:设标志或唤醒
源码中 public void interrupt() 的逻辑很清晰:
- 若目标线程正在运行(RUNNABLE)或锁竞争中(BLOCKED),仅调用
interrupt0()(native 方法)设置中断标志位,不抛异常、不终止线程 - 若目标线程正阻塞在
sleep()、wait()或join()上,JVM 会立即唤醒它,并在返回前抛出InterruptedException,同时**自动清除中断标志**(即后续调用isInterrupted()返回false) - 该方法不检查线程是否存活,对已终止线程调用无效果
不同阻塞点的响应由 JVM 底层状态机决定
不是 Java 代码“选择”怎么响应,而是 JVM 根据线程当前的 线程状态(Thread State) 和 阻塞原语类型 触发不同路径:
-
SLEEP / WAIT / JOIN 状态(TIMED_WAITING / WAITING):统一走 ObjectMonitor 或 ParkEvent 唤醒路径,强制抛
InterruptedException,清标志 -
NIO 阻塞(InterruptibleChannel):不抛
InterruptedException,而是关闭通道、抛ClosedByInterruptException,保留中断标志 -
Selector.select() 阻塞:不抛异常,仅设标志 + 唤醒 select,需手动判断
Thread.interrupted()是否为true -
RUNNABLE 状态下的忙循环:完全无反应,只设标志,必须靠代码显式调用
isInterrupted()检查
isInterrupted() 和 interrupted() 的区别藏在 native 层
这两个方法都调用同一个 native 方法 isInterrupted(boolean clear),区别全在参数:
-
isInterrupted()传false→ 只读,不改标志 -
interrupted()是静态方法,传true→ 读完立刻清标志,且只作用于当前线程
这个设计让上层能安全地“消费”一次中断信号,比如在 catch 块里调用 Thread.interrupted() 判断是否因中断退出,同时避免重复响应。
真正起作用的是程序员写的响应逻辑
源码不会替你退出循环或释放资源。标准实践模式在 JDK 自身类库中反复出现:
- 在 while 循环条件中写
!Thread.currentThread().isInterrupted() - 捕获
InterruptedException后,不做空 catch,而是:
✓ 调用Thread.currentThread().interrupt()恢复标志(供外层处理)
✓ 执行清理(如关闭流、回滚事务)
✓ 显式 return 或 break - 对不可中断操作(如 native I/O、synchronized 区域),记录中断意图并在安全点检查











