关于高并发:Interrupted-Exception异常可能没你想的那么简单

43次阅读

共计 2713 个字符,预计需要花费 7 分钟才能阅读完成。

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

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

正文完
 0