1. 程式人生 > >我們該如何正確的中斷一個執行緒的執行??

我們該如何正確的中斷一個執行緒的執行??

## 寫在前面 > 當我們在呼叫Java物件的wait()方法或者執行緒的sleep()方法時,需要捕獲並處理InterruptedException異常。如果我們對InterruptedException異常處理不當,則會發生我們意想不到的後果!今天,我們就以一個案例的形式,來為大家詳細介紹下為何中斷執行的執行緒不起作用。 > > 文章已收錄到:[https://github.com/sunshinelyz/technology-binghe](https://github.com/sunshinelyz/technology-binghe) 和 [https://gitee.com/binghe001/technology-binghe](https://gitee.com/binghe001/technology-binghe) ## 程式案例 例如,下面的程式程式碼,InterruptedTask類實現了Runnable介面,在run()方法中,獲取當前執行緒的控制代碼,並在while(true)迴圈中,通過isInterrupted()方法來檢測當前執行緒是否被中斷,如果當前執行緒被中斷就退出while(true)迴圈,同時,在while(true)迴圈中,還有一行Thread.sleep(100)程式碼,並捕獲了InterruptedException異常。整個程式碼如下所示。 ```java 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(); } } } } ``` 上述程式碼的本意是通過isInterrupted()方法檢查執行緒是否被中斷了,如果中斷了就退出while迴圈。其他執行緒通過呼叫執行執行緒的interrupt()方法來中斷執行執行緒,此時會設定執行執行緒的中斷標誌位,從而使currentThread.isInterrupted()返回true,這樣就能夠退出while迴圈。 這看上去沒啥問題啊!**但真的是這樣嗎?**我們建立一個InterruptedTest類用於測試,程式碼如下所示。 ```java 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方法,如下所示。 ![](https://img-blog.csdnimg.cn/20201220225754597.jpg) **這竟然跟我們想象的不一樣!不一樣!不一樣!這是為什麼呢?** ## 問題分析 上述程式碼明明呼叫了執行緒的interrupt()方法來中斷執行緒,但是卻並沒有起到啥作用。原因是執行緒的run()方法在執行的時候,大部分時間都是阻塞在sleep(100)上,當其他執行緒通過呼叫執行執行緒的interrupt()方法來中斷執行執行緒時,大概率的會觸發InterruptedException異常,**在觸發InterruptedException異常的同時,JVM會同時把執行緒的中斷標誌位清除,所以,這個時候在run()方法中判斷的currentThread.isInterrupted()會返回false,也就不會退出當前while迴圈了。** 既然問題分析清除了,**那如何中斷執行緒並退出程式呢?** ## 問題解決 **正確的處理方式應該是在InterruptedTask類中的run()方法中的while(true)迴圈中捕獲異常之後重新設定中斷標誌位**,所以,正確的InterruptedTask類的程式碼如下所示。 ```java 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(); } } } } ``` 可以看到,我們在捕獲InterruptedException異常的catch程式碼塊中新增了一行程式碼。 ```java currentThread.interrupt(); ``` 這就使得我們**捕獲到InterruptedException異常後,能夠重新設定執行緒的中斷標誌位,從而中斷當前執行的執行緒。** 我們再次執行InterruptedTest類的main方法,如下所示。 ![](https://img-blog.csdnimg.cn/20201220225818561.jpg) ## 總結 **處理InterruptedException異常時要小心,如果在呼叫執行執行緒的interrupt()方法中斷執行執行緒時,丟擲了InterruptedException異常,則在觸發InterruptedException異常的同時,JVM會同時把執行執行緒的中斷標誌位清除,此時呼叫執行執行緒的isInterrupted()方法時,會返回false。此時,正確的處理方式是在執行執行緒的run()方法中捕獲到InterruptedException異常,並重新設定中斷標誌位(也就是在捕獲InterruptedException異常的catch程式碼塊中,重新呼叫當前執行緒的interrupt()方法)。** **好了,今天就到這兒吧,我是冰河,我們下期見~~** ## 重磅福利 微信搜一搜【冰河技術】微信公眾號,關注這個有深度的程式設計師,每天閱讀超硬核技術乾貨,公眾號內回覆【PDF】有我準備的一線大廠面試資料和我原創的超硬核PDF技術文件,以及我為大家精心準備的多套簡歷模板(不斷更新中),希望大家都能找到心儀的工作,學習是一條時而鬱鬱寡歡,時而開懷大笑的路,加油。如果你通過努力成功進入到了心儀的公司,一定不要懈怠放鬆,職場成長和新技術學習一樣,不進則退。如果有幸我們江湖再見! 另外,我開源的各個PDF,後續我都會持續更新和維護,感謝大家長期以來對冰河的支援!!