抛出InterruptedException时线程中断状态未清除?程序为何多次输出interrupted
为什么程序会多次打印“interrupted”?
这是个很有意思的问题,核心原因是线程池的shutdownNow()操作和Thread.sleep()的异常处理之间存在竞态条件,导致线程的中断状态在被清除后又被重新设置了。
让我们一步步拆解逻辑:
先明确基础规则
根据Java官方文档,Thread.sleep()抛出InterruptedException时,确实会清除当前线程的中断状态——也就是说,刚进入catch块时,Thread.currentThread().isInterrupted()应该返回false。
但你的场景里发生了什么?
你的代码中,executor2.shutdownNow()会遍历线程池里的所有工作线程,对每个线程调用interrupt()。这里的关键是:线程池的中断操作不是一次性完成的,而且线程调度存在延迟,可能出现以下时序:
- 工作线程执行
Thread.sleep(1000*100),此时被线程池的interrupt()中断,抛出InterruptedException,同时清除线程的中断状态。 - 线程进入
catch块,但还没执行到if (Thread.currentThread().isInterrupted())这行代码。 - 线程池的管理逻辑再次对这个工作线程执行了
interrupt()(可能是线程池在清理工作线程时的额外操作,或者是调度延迟导致中断信号在异常抛出后才到达线程)。 - 此时执行
isInterrupted(),发现中断状态已经被重新设置为true,于是打印“interrupted”。
怎么验证这个猜想?
你可以修改catch块的代码,分两次打印中断状态:
catch (InterruptedException e) { // 刚抛出异常时的状态,应该是false System.out.println("刚进入catch: " + Thread.currentThread().isInterrupted()); // 稍微等一下,让线程池的中断操作有机会触发 try { Thread.sleep(50); } catch (InterruptedException ex) {} // 再次检查,大概率会变成true System.out.println("等待后: " + Thread.currentThread().isInterrupted()); }
运行后你会看到,很多线程的第一次打印是false,第二次是true——这就证明了线程在catch块中被再次中断了。
额外补充
线程池的工作线程是循环复用的,当一个任务执行完毕后,工作线程会回到线程池的任务队列中等待下一个任务。shutdownNow()不仅会中断正在执行的任务,还会标记线程池为终止状态,后续工作线程在检查状态时也可能被中断。这种多阶段的中断操作,就导致了你的代码中出现多次“interrupted”打印。
内容的提问来源于stack exchange,提问作者newuser
相关产品推荐
相关产品推荐

