当前位置: 首页 > 后端技术 > Java

InterruptedException可能没有你想的那么简单!

时间:2023-04-02 09:33:24 Java

摘要:当我们调用Java对象的wait()方法或线程的sleep()方法时,需要捕获并处理InterruptedException异常。如果我们不正确处理InterruptedException,就会出现意想不到的后果!本文分享自华为云社区《【高并发】由InterruptedException异常引发的思考》,作者:冰河。前言当我们调用Java对象的wait()方法或线程的sleep()方法时,我们需要捕获并处理InterruptedException异常。如果我们对InterruptedException处理不当,就会出现意想不到的后果!程序示例例如,在下面的程序代码中,InterruptedTask类实现了Runnable接口。在run()方法中获取当前线程的句柄,在while(true)循环中使用isInterrupted()方法检测当前线程是否被中断。中断,如果当前线程被中断,则退出while(true)循环。同时,在while(true)循环中,有一行Thread.sleep(100)的代码,捕获了InterruptedException。整个代码如下所示。packageio.binghe.concurrent.lab08;/***@authorbinghe*@version1.0.0*@description线程测试中断*/publicclassInterruptedTaskimplementsRunnable{@Overridepublicvoidrun(){ThreadcurrentThread=Thread.当前线程();while(true){if(currentThread.isInterrupted()){中断;}尝试{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}}}}上面代码的初衷是通过isInterrupted()方法检查线程是否被中断,如果被中断则退出while循环。其他线程通过调用执行线程的interrupt()方法中断执行线程。这时会设置执行线程的中断标志位,使currentThread.isInterrupted()返回true,从而可以退出while循环。这看起来不错!但事实真的如此吗?我们创建一个InterruptedTest类进行测试,代码如下所示。packageio.binghe.concurrent.lab08;/***@authorbinghe*@version1.0.0*@description测试线程中断*/publicclassInterruptedTest{publicstaticvoidmain(String[]args){InterruptedTaskinterruptedTask=newInterruptedTask();线程interruptedThread=newThread(interruptedTask);中断线程.start();尝试{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}interruptedThread.interrupt();如下所示运行主要方法。原来和我们想象的不一样啊!不一样!不一样!为什么是这样?问题分析上面的代码明明调用了线程的interrupt()方法来中断线程,但是并没有起作用。原因是线程的run()方法执行时,大部分时间都阻塞在sleep(100)上。当其他线程通过调用执行线程的interrupt()方法中断执行线程时,大概率会触发Interrupted。异常是不正常的。当InterruptedException被触发时,JVM会同时清除线程的中断标志。所以,此时在run()方法中判断的当前Thread.isInterrupted()会返回false,不会退出当前线程。while循环。既然问题分析清楚了,那么如何中断线程退出程序呢?正确的解决方法是在InterruptedTask类的run()方法中的while(true)循环中捕捉到异常后,重新设置中断标志位。因此,正确的InterruptedTask类代码如下。packageio.binghe.concurrent.lab08;/***@authorbinghe*@version1.0.0*@description中断线程测试*/publicclassInterruptedTaskimplementsRunnable{@Overridepublicvoidrun(){ThreadcurrentThread=Thread.currentThread();while(true){if(currentThread.isInterrupted()){中断;}尝试{Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();当前线程.中断();}}}}可以看到,我们在catch代码块中新增了一行代码,用于捕获InterruptedException异常。当前线程.中断();这样我们就可以在捕获到InterruptedException后,重新设置线程的中断标志位,从而中断当前正在执行的线程。我们再次运行中断测试类的主要方法,如下所示。总结处理中断异常时要小心。如果在调用执行线程的interrupt()方法中断执行线程时抛出InterruptedException,JVM会在InterruptedException触发时同时设置执行线程的中断标志。清楚了,此时调用执行线程的isInterrupted()方法时,会返回false。这时正确的处理方式是在执行线程的run()方法中捕获InterruptedException,并重置中断标志位(即在捕获InterruptedException的catch代码块中,重新-调用当前线程的中断()方法)。点击关注,第一时间了解华为云的新鲜技术~

最新推荐
猜你喜欢