摘要: 当咱们在调用Java对象的wait()办法或者线程的sleep()办法时,须要捕捉并解决InterruptedException异样。如果咱们对InterruptedException异样处理不当,则会产生咱们意想不到的结果!
本文分享自华为云社区《【高并发】由InterruptedException异样引发的思考》,作者:冰 河。
前言
当咱们在调用Java对象的wait()办法或者线程的sleep()办法时,须要捕捉并解决Interrupted Exception异样。如果咱们对Interrupted Exception异样处理不当,则会产生咱们意想不到的结果!
程序案例
例如,上面的程序代码,Interrupted Task类实现了Runnable接口,在run()办法中,获取以后线程的句柄,并在while(true)循环中,通过isInterrupted()办法来检测以后线程是否被中断,如果以后线程被中断就退出while(true)循环,同时,在while(true)循环中,还有一行Thread.sleep(100)代码,并捕捉了Interrupted Exception异样。整个代码如下所示。
package io.binghe.concurrent.lab08;/** * @author binghe * @version 1.0.0 * @description 线程测试中断 */public class Interrupted Task implements Runnable{ @Override public void run() { Thread currentThread = Thread.currentThread(); while (true){ if(currentThread.isInterrupted()){ break; } try { Thread.sleep(100); } catch (Interrupted Exception e) { e.printStack Trace(); } } }}
上述代码的本意是通过isInterrupted()办法查看线程是否被中断了,如果中断了就退出while循环。其余线程通过调用执行线程的interrupt()办法来中断执行线程,此时会设置执行线程的中断标记位,从而使currentThread.isInterrupted()返回true,这样就可能退出while循环。
这看上去没啥问题啊!但真的是这样吗?咱们创立一个Interrupted Test类用于测试,代码如下所示。
package io.binghe.concurrent.lab08;/** * @author binghe * @version 1.0.0 * @description 测试线程中断 */public class InterruptedTest { public static void main(String[] args){ InterruptedTask interruptedTask = new InterruptedTask(); Thread interruptedThread = new Thread(interruptedTask); interruptedThread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } interruptedThread.interrupt(); }}
咱们运行main办法,如下所示。
这居然跟咱们设想的不一样!不一样!不一样!这是为什么呢?
问题剖析
上述代码明明调用了线程的interrupt()办法来中断线程,然而却并没有起到啥作用。起因是线程的run()办法在执行的时候,大部分工夫都是阻塞在sleep(100)上,当其余线程通过调用执行线程的interrupt()办法来中断执行线程时,大概率的会触发Interrupted Exception异样,在触发Interrupted Exception异样的同时,JVM会同时把线程的中断标记位革除,所以,这个时候在run()办法中判断的current Thread.isInterrupted()会返回false,也就不会退出以后while循环了。
既然问题剖析革除了,那如何中断线程并退出程序呢?
问题解决
正确的解决形式应该是在Interrupted Task类中的run()办法中的while(true)循环中捕捉异样之后从新设置中断标记位,所以,正确的Interrupted Task类的代码如下所示。
package io.binghe.concurrent.lab08;/** * @author binghe * @version 1.0.0 * @description 中断线程测试 */public class InterruptedTask implements Runnable{ @Override public void run() { Thread currentThread = Thread.currentThread(); while (true){ if(currentThread.isInterrupted()){ break; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); currentThread.interrupt(); } } }}
能够看到,咱们在捕捉Interrupted Exception异样的catch代码块中新增了一行代码。
currentThread.interrupt();
这就使得咱们捕捉到Interrupted Exception异样后,可能从新设置线程的中断标记位,从而中断以后执行的线程。
咱们再次运行Interrupted Test类的main办法,如下所示。
总结
解决Interrupted Exception异样时要小心,如果在调用执行线程的interrupt()办法中断执行线程时,抛出了Interrupted Exception异样,则在触发Interrupted Exception异样的同时,JVM会同时把执行线程的中断标记位革除,此时调用执行线程的isInterrupted()办法时,会返回false。此时,正确的解决形式是在执行线程的run()办法中捕捉到Interrupted Exception异样,并从新设置中断标记位(也就是在捕捉Interrupted Exception异样的catch代码块中,从新调用以后线程的interrupt()办法)。
点击关注,第一工夫理解华为云陈腐技术~