當咱們在調用Java對象的wait()方法或者線程的sleep()方法時,須要捕獲並處理InterruptedException異常。若是咱們對InterruptedException異常處理不當,則會發生咱們意想不到的後果!今天,咱們就以一個案例的形式,來爲你們詳細介紹下爲什麼中斷執行的線程不起做用。java
文章已收錄到:https://github.com/sunshinelyz/technology-binghe 和 https://gitee.com/binghe001/technology-binghegit
例如,下面的程序代碼,InterruptedTask類實現了Runnable接口,在run()方法中,獲取當前線程的句柄,並在while(true)循環中,經過isInterrupted()方法來檢測當前線程是否被中斷,若是當前線程被中斷就退出while(true)循環,同時,在while(true)循環中,還有一行Thread.sleep(100)代碼,並捕獲了InterruptedException異常。整個代碼以下所示。程序員
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循環。github
這看上去沒啥問題啊!但真的是這樣嗎?咱們建立一個InterruptedTest類用於測試,代碼以下所示。面試
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方法,以下所示。微信
這居然跟咱們想象的不同!不同!不同!這是爲何呢?ide
上述代碼明明調用了線程的interrupt()方法來中斷線程,可是卻並無起到啥做用。緣由是線程的run()方法在執行的時候,大部分時間都是阻塞在sleep(100)上,當其餘線程經過調用執行線程的interrupt()方法來中斷執行線程時,大機率的會觸發InterruptedException異常,在觸發InterruptedException異常的同時,JVM會同時把線程的中斷標誌位清除,因此,這個時候在run()方法中判斷的currentThread.isInterrupted()會返回false,也就不會退出當前while循環了。學習
既然問題分析清除了,那如何中斷線程並退出程序呢?測試
正確的處理方式應該是在InterruptedTask類中的run()方法中的while(true)循環中捕獲異常以後從新設置中斷標誌位,因此,正確的InterruptedTask類的代碼以下所示。線程
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代碼塊中新增了一行代碼。
currentThread.interrupt();
這就使得咱們捕獲到InterruptedException異常後,可以從新設置線程的中斷標誌位,從而中斷當前執行的線程。
咱們再次運行InterruptedTest類的main方法,以下所示。
處理InterruptedException異常時要當心,若是在調用執行線程的interrupt()方法中斷執行線程時,拋出了InterruptedException異常,則在觸發InterruptedException異常的同時,JVM會同時把執行線程的中斷標誌位清除,此時調用執行線程的isInterrupted()方法時,會返回false。此時,正確的處理方式是在執行線程的run()方法中捕獲到InterruptedException異常,並從新設置中斷標誌位(也就是在捕獲InterruptedException異常的catch代碼塊中,從新調用當前線程的interrupt()方法)。
好了,今天就到這兒吧,我是冰河,咱們下期見~~
微信搜一搜【冰河技術】微信公衆號,關注這個有深度的程序員,天天閱讀超硬核技術乾貨,公衆號內回覆【PDF】有我準備的一線大廠面試資料和我原創的超硬核PDF技術文檔,以及我爲你們精心準備的多套簡歷模板(不斷更新中),但願你們都能找到心儀的工做,學習是一條時而鬱鬱寡歡,時而開懷大笑的路,加油。若是你經過努力成功進入到了心儀的公司,必定不要懈怠放鬆,職場成長和新技術學習同樣,不進則退。若是有幸咱們江湖再見!
另外,我開源的各個PDF,後續我都會持續更新和維護,感謝你們長期以來對冰河的支持!!