中断阻塞/睡眠线程的行为及程序运行异常疑惑
Java线程中断问题深度解析
一、待解答问题
1. 基础问题
中断处于阻塞或睡眠状态的线程会发生什么?
2. 选择题
当对因调用join、sleep或wait方法而阻塞的线程调用interrupt方法后,会发生以下哪种情况?
选项:
- 线程进入非可运行状态
- 线程退出非可运行状态
- 线程进入运行状态时抛出
InterruptedException - 抛出
InterruptedException后调用Thread.interrupted()会返回true - 以上都不是
二、测试程序与输出
Program 1
public class JavaApplication1 { public static void main(String[] args) { try { Thread.sleep(2000); boolean interrupted = Thread.interrupted(); System.out.println(interrupted); Thread currentThread = Thread.currentThread(); System.out.println("Current Thread ID : " + currentThread.getId()); System.out.println("State : " + currentThread.getState()); Thread t = new Thread(() -> System.out.println("runnable target")); System.out.println("Thread t not started yet : " + t.getState()); System.out.println("Thread t not started yet : " + t.isAlive()); System.out.println("T id : " + t.getId()); Thread t2 = new Thread(() -> { for (int i = 0; i < 10; i++) { try { System.out.println("runnable target"); if (i == 5) { Thread.sleep(2000); } } catch (InterruptedException ex) { Logger.getLogger(JavaApplication1.class.getName()).log(Level.SEVERE, null, ex); } } }); t2.start(); System.out.println("T id : " + t2.getId()); System.out.println("default priority : " + t2.getPriority()); System.out.println("interrupting the main thread---"); currentThread.interrupt(); System.out.println("Current Thread ID : " + currentThread.getId()); System.out.println("State : " + currentThread.getState()); System.out.println("State : " + currentThread.isInterrupted()); System.out.println("interrupting the t2 thread---"); t2.interrupt(); System.out.println("Current Thread ID : " + t2.getId()); System.out.println("State : " + t2.getState()); System.out.println("State : " + t2.isInterrupted()); } catch (InterruptedException ex) { System.out.println("Interrupted Exception :" + ex); } } }
Program 1 输出
false Current Thread ID : 1 State : RUNNABLE Thread t not started yet : NEW Thread t not started yet : false T id : 10 T id : 11 default priority : 5 interrupting the main thread--- Current Thread ID : 1 State : RUNNABLE State : true interrupting the t2 thread--- Current Thread ID : 11 State : RUNNABLE State : true runnable target runnable target runnable target runnable target runnable target runnable target runnable target runnable target runnable target Jan 12, 2018 3:36:43 PM javaapplication1.JavaApplication1 lambda$main$1 runnable target SEVERE: null java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at javaapplication1.JavaApplication1.lambda$main$1(JavaApplication1.java:27) at java.lang.Thread.run(Thread.java:748)
Program 2
public class JavaApplication1 { public static void main(String[] args) { try { Thread.sleep(2000); boolean interrupted = Thread.interrupted(); System.out.println(interrupted); Thread currentThread = Thread.currentThread(); System.out.println("Current Thread ID : " + currentThread.getId()); System.out.println("State : " + currentThread.getState()); Thread t = new Thread(() -> System.out.println("runnable target")); System.out.println("Thread t not started yet : " + t.getState()); System.out.println("Thread t not started yet : " + t.isAlive()); System.out.println("T id : " + t.getId()); Thread t2 = new Thread(() -> { for (int i = 0; i < 10; i++) { try { System.out.println("runnable target"); if (i == 5) { System.out.println("t2 interrupted? "+Thread.interrupted()); System.out.println("State : "+currentThread.getState()); Thread.sleep(2000); } } catch (InterruptedException ex) { Logger.getLogger(JavaApplication1.class.getName()).log(Level.SEVERE, null, ex); } } }); t2.start(); System.out.println("T id : " + t2.getId()); System.out.println("default priority : " + t2.getPriority()); System.out.println("interrupting the main thread---"); currentThread.interrupt(); System.out.println("Current Thread ID : " + currentThread.getId()); System.out.println("State : " + currentThread.getState()); System.out.println("is interrupted : " + currentThread.isInterrupted()); System.out.println("interrupting the t2 thread---"); t2.interrupt(); System.out.println("Current Thread ID : " + t2.getId()); System.out.println("State : " + t2.getState()); System.out.println("is interrupted : " + t2.isInterrupted()); } catch (InterruptedException ex) { System.out.println("Interrupted Exception :" + ex); } } }
Program 2 输出
false Current Thread ID : 1 State : RUNNABLE Thread t not started yet : NEW Thread t not started yet : false T id : 10 T id : 11 default priority : 5 interrupting the main thread--- Current Thread ID : 1 State : RUNNABLE State : true interrupting the t2 thread--- Current Thread ID : 11 State : RUNNABLE is interrupted : true runnable target runnable target runnable target runnable target runnable target runnable target t2 interrupted? true is interrupted : TERMINATED runnable target runnable target runnable target runnable target
三、用户的选择与疑惑
我选择了选项2和3,理由是:Program2中线程状态为TERMINATED,Program1中t2线程状态为RUNNABLE且抛出sleep中断异常。但我存在疑惑:如果t2线程状态是TERMINATED,为何末尾还打印了4次“runnable target”?线程处于TERMINATED状态难道不应该停止运行吗?
四、问题解答
1. 中断阻塞/睡眠线程的行为
当线程因sleep、join或wait进入阻塞状态时,调用其interrupt()方法会:
- 立即清除线程的中断状态(注意:
Thread.interrupted()会主动清除状态,而isInterrupted()仅查询不清除) - 抛出
InterruptedException,让线程从阻塞状态退出,回到RUNNABLE状态,此时可以捕获异常并处理后续逻辑
2. 选择题正确选项分析
我们逐个拆解选项:
- 选项1(进入非可运行状态):错误,中断的作用是让线程退出阻塞(非可运行)状态,而非进入。
- 选项2(退出非可运行状态):正确,阻塞状态属于非可运行状态范畴,中断会触发线程从该状态退出。
- 选项3(进入运行状态时抛出InterruptedException):正确,线程被中断后从阻塞中唤醒,此时处于
RUNNABLE状态并抛出该异常。 - 选项4(抛出异常后调用Thread.interrupted()返回true):错误,抛出
InterruptedException时JVM会自动清除线程的中断状态,所以Thread.interrupted()会返回false(除非后续线程再次被中断)。 - 选项5(以上都不是):错误,选项2和3均正确。
3. 关于Program2中TERMINATED状态却仍打印的疑惑
你看到的TERMINATED状态不是t2线程的,而是main线程的!仔细看Program2中t2的lambda代码:
System.out.println("State : "+currentThread.getState());
这里的currentThread是在main方法中初始化的Thread.currentThread(),它始终指向main线程,而非t2自身。
当t2执行到这行代码时,main线程可能已经执行完所有逻辑(main线程在调用t2.interrupt()后没有其他任务,很快就结束并进入TERMINATED状态)。而t2线程此时还在继续执行for循环的剩余迭代,所以会继续打印“runnable target”,直到循环完成10次后才会终止。
内容的提问来源于stack exchange,提问作者Dilini Peiris
相关产品推荐
相关产品推荐

