摘要: 当咱们在调用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()办法)。

点击关注,第一工夫理解华为云陈腐技术~