必須要掌握的 InterruptedException 異常處理

點擊上方 "程序員小樂"關注, 星標或置頂一起成長

每天凌晨00點00分, 第一時間與你相約


每日英文

Always remember that your present situation is not your final destination. The best is yet to come.

要記住你現在的處境並不是你最終的歸屬,最好的尚未到來。


每日掏心話

別人在熬夜時,你在睡覺,別人已經起床,你還在掙扎再多睡幾分鐘,你有很多想法,但腦袋熱了就過了,別人卻一件事堅持到底。你連一本書都要看很久,該工作的時候就刷起手機,肯定也不能早晨起來背單詞,晚上加班到深夜。很多時候不是你平凡,碌碌無為,而是你沒有別人付出得多。


來自:不學無數的程序員 | 責編:樂樂

鏈接:jianshu.com/p/a8abe097d4ed

必須要掌握的 InterruptedException 異常處理

程序員小樂(ID:study_tech)第 799 次推文 圖片來自百度


往日回顧:注意!2月份工資有變化,必須這麼發工資!


正文


InterruptedException異常

在瞭解InterruptedException異常之前應該瞭解以下的幾個關於線程的一些基礎知識。而且得知道什麼時候會拋InterruptedException異常。

當阻塞方法收到中斷請求的時候就會拋出InterruptedException異常。

線程的狀態

線程在一定的條件下會發生狀態的改變,下面是線程的一些狀態

必須要掌握的 InterruptedException 異常處理


  • 初始(NEW):新建一個線程的對象,還未調用start方法

  • 運行(RUNNABLE):java線程中將已經準備就緒(Ready)和正在運行中(Running)的兩種狀態都統稱為“Runnable”。準備就緒的線程會被放在線程池中等待被調用

  • 阻塞(BLOCKED):是因為某種的原因而放棄了CPU的使用權,暫時的停止了運行。直到線程進入準備就緒(Ready)狀態才會有機會轉到運行狀態

  • 等待(WAITING):該狀態的線程需要等待其他線程做出一些特定的動作(通知或者是中斷)

  • 超時等待(TIME_WAITING):該狀態和上面的等待不同,他可以在指定的時間內自行返回

  • 終止(TERMINATED):線程任務執行完畢


而InterruptedException異常從字面意思上就是中斷異常,那麼什麼是中斷呢?學習中斷之前我們先了解一下具體什麼是阻塞

線程阻塞

線程阻塞通常是指一個線程在執行過程中暫停,以等待某個條件的觸發。而什麼情況才會使得線程進入阻塞的狀態呢?


  • 等待阻塞:運行的線程執行wait()方法,該線程會釋放佔用的所有資源,JVM會把該線程放入“等待池”中。進入這個狀態後,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒

  • 同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入“鎖池”中

  • 其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態


線程中斷

如果我們有一個運行中的軟件,例如是殺毒軟件正在全盤查殺病毒,此時我們不想讓他殺毒,這時候點擊取消,那麼就是正在中斷一個運行的線程。

每一個線程都有一個boolean類型的標誌,此標誌意思是當前的請求是否請求中斷,默認為false。當一個線程A調用了線程B的interrupt方法時,那麼線程B的是否請求的中斷標誌變為true。而線程B可以調用方法檢測到此標誌的變化。


  • 阻塞方法:如果線程B調用了阻塞方法,如果是否請求中斷標誌變為了true,那麼它會拋出InterruptedException異常。拋出異常的同時它會將線程B的是否請求中斷標誌置為false

  • 非阻塞方法:可以通過線程B的isInterrupted方法進行檢測是否請求中斷標誌為true還是false,另外還有一個靜態的方法interrupted方法也可以檢測標誌。但是靜態方法它檢測完以後會自動的將是否請求中斷標誌位置為false。例如線程A調用了線程B的interrupt的方法,那麼如果此時線程B中用靜態interrupted方法進行檢測標誌位的變化的話,那麼第一次為true,第二次就為false。下面為具體的例子:


  • /**


  • * @program: Test


  • * @description:


  • * @author: [email protected]


  • * @create: 2018-07-31 15:43


  • **/


  • public class InterrupTest implements Runnable{



  • public void run(){


  • try {


  • while (true) {


  • Boolean a = Thread.currentThread().isInterrupted();


  • System.out.println("in run() - about to sleep for 20 seconds-------" + a);


  • Thread.sleep(20000);


  • System.out.println("in run() - woke up");


  • }


  • } catch (InterruptedException e) {


  • Thread.currentThread().interrupt();//如果不加上這一句,那麼cd將會都是false,因為在捕捉到InterruptedException異常的時候就會自動的中斷標誌置為了false


  • Boolean c=Thread.interrupted();


  • Boolean d=Thread.interrupted();


  • System.out.println("c="+c);


  • System.out.println("d="+d);


  • }


  • }


  • public static void main(String[] args) {


  • InterrupTest si = new InterrupTest();


  • Thread t = new Thread(si);


  • t.start();


  • //主線程休眠2秒,從而確保剛才啟動的線程有機會執行一段時間


  • try {


  • Thread.sleep(2000);


  • }catch(InterruptedException e){


  • e.printStackTrace();


  • }


  • System.out.println("in main() - interrupting other thread");


  • //中斷線程t


  • t.interrupt();


  • System.out.println("in main() - leaving");


  • }


  • }



打印的參數如下:

in run() - about to sleep for 20 seconds-------false
in main() - interrupting other thread
in main() - leaving
c=true
d=false

現在知道線程可以檢測到自身的標誌位的變化,但是他只是一個標誌,如果線程本身不處理的話,那麼程序還是會執行下去,就好比,老師在學校叮囑要好好學習,具體什麼時候,如何好好學習還是看自身。

因此interrupt() 方法並不能立即中斷線程,該方法僅僅告訴線程外部已經有中斷請求,至於是否中斷還取決於線程自己

InterruptedException異常的處理

簡單的瞭解了什麼是阻塞和中斷以後,我們就該瞭解碰到InterruptedException異常該如何處理了。

不要不管不顧

有時候阻塞的方法拋出InterruptedException異常並不合適,例如在Runnable中調用了可中斷的方法,因為你的程序是實現了Runnable接口,然後在重寫Runnable接口的run方法的時候,那麼子類拋出的異常要小於等於父類的異常。

而在Runnable中run方法是沒有拋異常的。所以此時是不能拋出InterruptedException異常。如果此時你只是記錄日誌的話,那麼就是一個不負責任的做法,因為在捕獲InterruptedException異常的時候自動的將是否請求中斷標誌置為了false。

至少在捕獲了InterruptedException異常之後,如果你什麼也不想做,那麼就將標誌重新置為true,以便棧中更高層的代碼能知道中斷,並且對中斷作出響應。

捕獲到InterruptedException異常後恢復中斷狀態

public class TaskRunner implements Runnable {
private BlockingQueue<task> queue;

public TaskRunner(BlockingQueue<task> queue) {
this.queue = queue;
}

public void run() {
try {
while (true) {
Task task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
/<task>/<task>

參考文章

blog.csdn.net/sinat_34596644/article/details/51405327
blog.csdn.net/u011784767/article/details/51428101
ibm.com/developerworks/cn/java/j-jtp05236.html
blog.csdn.net/pange1991/article/details/53860651


必須要掌握的 InterruptedException 異常處理

歡迎在留言區留下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,學習能力的提升上有新的認識,歡迎轉發分享給更多人。


猜你還想看


阿里、騰訊、百度、華為、京東最新面試題彙集

你能說出多線程中 sleep、yield、join 的用法及 sleep與wait區別嗎?

Git 居然還有這麼高級用法,你一定需要

Java編程性能優化一些事兒

關注訂閱號「程序員小樂」,收看更多精彩內容
嘿,你在看嗎?


分享到:


相關文章: