sleep()、wait()、join()被interrupt()中断时立即抛出interruptedexception并自动清除中断状态;nio阻塞操作不抛此异常,而是关闭通道或使select()返回;runnable/blocked状态下interrupt()仅设标志位,需主动检查isinterrupted()响应。

sleep() 被 interrupt() 中断时会立即抛出 InterruptedException
调用 Thread.sleep() 进入 TIMED_WAITING 状态后,一旦被其他线程调用 interrupt(),JVM 会立刻唤醒该线程,并抛出 InterruptedException,同时**自动清除中断状态(即 isInterrupted() 随后返回 false)**。
常见错误是捕获异常后直接忽略或只打印日志,导致线程继续执行后续逻辑——这违背了中断本意。正确做法是在 catch 块中做清理并退出,或重新设置中断状态:
- 不要写
catch (InterruptedException e) { e.printStackTrace(); } - 推荐写法:
catch (InterruptedException e) { Thread.currentThread().interrupt(); return; }(保留中断信号供上层处理) - 若在循环中调用
sleep(),需确保每次迭代前检查Thread.currentThread().isInterrupted()
wait() / join() 的中断行为与 sleep() 高度一致
Object.wait()、Thread.join() 同样使线程进入 WAITING 或 TIMED_WAITING 状态,interrupt() 触发后也抛出 InterruptedException,且同样**自动清除中断标志**。
关键差异在于语义和上下文:
-
wait()必须在同步块内调用,中断后需注意锁是否仍持有——JVM 保证锁不会因中断而丢失,但业务逻辑可能依赖 wait 条件,需重检条件再决定是否继续等待 -
join()中断后,调用方线程不再等待目标线程结束,但目标线程本身不受影响(除非它自己也响应中断) - 所有这三类方法(
sleep/wait/join)的throws InterruptedException是强制契约,不可声明为throws Exception或吞掉异常
NIO Channel 和 Selector 的中断响应更底层、不抛标准异常
当线程阻塞在 InterruptibleChannel(如 FileChannel、SocketChannel)的读写操作上时,interrupt() 不会抛 InterruptedException,而是:
- 关闭该 channel(触发
ClosedByInterruptException) - 设置线程中断状态(
isInterrupted()返回true) - 线程从阻塞点返回,但需手动检查异常类型
而阻塞在 Selector.select() 上时,interrupt() 不抛异常,仅设置中断状态,并让 select() 立即返回(类似调用了 wakeup()),此时需结合 Thread.interrupted() 判断是否由中断引起返回。
容易踩的坑:
- 误以为 NIO 操作也会抛
InterruptedException,结果漏处理ClosedByInterruptException - 在
select()循环中只检查selectedKeys().size() > 0,忽略中断状态,导致无法及时退出 - 调用
interrupted()(静态方法)清除了状态,后续无法再通过isInterrupted()检测
RUNNABLE 和 BLOCKED 状态下 interrupt() 只设标志位,不强制终止
线程处于 RUNNABLE(正常计算、IO 密集但未进 NIO 阻塞点)或 BLOCKED(等待 synchronized 锁)时,interrupt() **仅设置中断状态为 true,不做任何其他动作**。
这意味着:
- 线程不会停下当前指令,也不会抛异常,必须靠主动轮询
isInterrupted()来响应 -
BLOCKED状态无法被中断——这是 Java 明确规定的,synchronized 锁等待不响应中断;若需可中断锁,必须改用Lock.lockInterruptibly() - 长时间运行的 CPU 密集型任务,若不插入
isInterrupted()检查,interrupt()就完全无效
最常被忽略的一点:很多开发者以为调用 interrupt() 就等于“发出了停止命令”,却没意识到在非阻塞路径上,这个命令根本不会被线程感知到——它只是个静默的布尔标记,需要你亲手去读、去响应、去退出。











