java面試-Java併發程式設計(五)——中斷
什麼是中斷?
在Java中沒有辦法立即停止一條執行緒,然而停止執行緒卻顯得尤為重要,如取消一個耗時操作。因此,Java提供了一種用於停止執行緒的機制——中斷。
- 中斷只是一種協作機制,Java沒有給中斷增加任何語法,中斷的過程完全需要程式設計師自己實現。若要中斷一個執行緒,你需要手動呼叫該執行緒的interrupted方法,該方法也僅僅是將執行緒物件的中斷標識設成true;接著你需要自己寫程式碼不斷地檢測當前執行緒的標識位;如果為true,表示別的執行緒要求這條執行緒中斷,此時究竟該做什麼需要你自己寫程式碼實現。
- 每個執行緒物件中都有一個標識,用於表示執行緒是否被中斷;該標識位為true表示中斷,為false表示未中斷;
- 通過呼叫執行緒物件的interrupt方法將該執行緒的標識位設為true;可以在別的執行緒中呼叫,也可以在自己的執行緒中呼叫。
中斷的相關方法
-
public void interrupt()
將呼叫者執行緒的中斷狀態設為true。 -
public boolean isInterrupted()
判斷呼叫者執行緒的中斷狀態。 -
public static boolean interrupted
只能通過Thread.interrupted()呼叫。
它會做兩步操作:- 返回當前執行緒的中斷狀態;
- 將當前執行緒的中斷狀態設為false;
暫停、繼續、停止執行緒(已過時)
以下三個方法都是通過執行緒物件去呼叫。
-
suspend()
暫停呼叫者執行緒,只釋放CPU執行權,不釋放鎖。
由於在不釋放資源的情況下進入睡眠狀態,容易產生死鎖。因此已過時! -
resume()
恢復呼叫者執行緒,讓他處於就緒狀態。 -
stop()
呼叫stop後,並不會保證資源被正確地釋放,它會使程式處於不正確的狀態下。
PS:stop和interrupt的區別?
中斷的使用
要使用中斷,首先需要在可能會發生中斷的執行緒中不斷監聽中斷狀態,一旦發生中斷,就執行相應的中斷處理程式碼。
當需要中斷執行緒時,呼叫該執行緒物件的interrupt函式即可。
設定中斷監聽
Thread t1 = new Thread( new Runnable(){
public void run(){
// 若未發生中斷,就正常執行任務
while(!Thread.currentThread.isInterrupted()){
// 正常任務程式碼……
}
// 中斷的處理程式碼……
doSomething();
}
} ).start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
正常的任務程式碼被封裝在while迴圈中,每次執行完一遍任務程式碼就檢查一下中斷狀態;一旦發生中斷,則跳過while迴圈,直接執行後面的中斷處理程式碼。
觸發中斷
t1.interrupt();
- 1
上述程式碼執行後會將t1物件的中斷狀態設為true,此時t1執行緒的正常任務程式碼執行完成後,進入下一次while迴圈前Thread.currentThread.isInterrupted()的結果為true,此時退出迴圈,執行迴圈後面的中斷處理程式碼。
安全地停止執行緒
stop函式停止執行緒過於暴力,它會立即停止執行緒,不給任何資源釋放的餘地,下面介紹兩種安全停止執行緒的方法。
迴圈標記變數
自定義一個共享的boolean型別變數,表示當前執行緒是否需要中斷。
- 中斷標識
volatile boolean interrupted = false;
- 1
- 任務執行函式
Thread t1 = new Thread( new Runnable(){
public void run(){
while(!interrupted){
// 正常任務程式碼……
}
// 中斷處理程式碼……
// 可以在這裡進行資源的釋放等操作……
}
} );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 中斷函式
Thread t2 = new Thread( new Runnable(){
public void run(){
interrupted = true;
}
} );
- 1
- 2
- 3
- 4
- 5
迴圈中斷狀態
-
中斷標識
由執行緒物件提供,無需自己定義。 -
任務執行函式
Thread t1 = new Thread( new Runnable(){
public void run(){
while(!Thread.currentThread.isInterrupted()){
// 正常任務程式碼……
}
// 中斷處理程式碼……
// 可以在這裡進行資源的釋放等操作……
}
} );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 中斷函式
t1.interrupt();
- 1
總結
上述兩種方法本質一樣,都是通過迴圈檢視一個共享標記為來判斷執行緒是否需要中斷,他們的區別在於:第一種方法的標識位是我們自己設定的,而第二種方法的標識位是Java提供的。除此之外,他們的實現方法是一樣的。
上述兩種方法之所以較為安全,是因為一條執行緒發出終止訊號後,接收執行緒並不會立即停止,而是將本次迴圈的任務執行完,再跳出迴圈停止執行緒。此外,程式設計師又可以在跳出迴圈後新增額外的程式碼進行收尾工作。
處理中斷
上文都在介紹如何獲取中斷狀態,那麼當我們捕獲到中斷狀態後,究竟如何處理呢?
- Java類庫中提供的一些可能會發生阻塞的方法都會拋InterruptedException異常,如:BlockingQueue#put、BlockingQueue#take、Object#wait、Thread#sleep。
- 當你在某一條執行緒中呼叫這些方法時,這個方法可能會被阻塞很長時間,你可以在別的執行緒中呼叫當前執行緒物件的interrupt方法觸發這些函式丟擲InterruptedException異常。
- 當一個函式丟擲InterruptedException異常時,表示這個方法阻塞的時間太久了,別人不想等它執行結束了。
- 當你的捕獲到一個InterruptedException異常後,亦可以處理它,或者向上丟擲。
- 丟擲時要注意???:當你捕獲到InterruptedException異常後,當前執行緒的中斷狀態已經被修改為false(表示執行緒未被中斷);此時你若能夠處理中斷,則不用理會該值;但如果你繼續向上拋InterruptedException異常,你需要再次呼叫interrupt方法,將當前執行緒的中斷狀態設為true。
- 注意:絕對不能“吞掉中斷”!即捕獲了InterruptedException而不作任何處理。這樣違背了中斷機制的規則,別人想讓你執行緒中斷,然而你自己不處理,也不將中斷請求告訴呼叫者,呼叫者一直以為沒有中斷請求。
QA
- 為什麼catch InterruptedException後會自動清除中斷狀態?
相關文章
- Java併發程式設計的藝術(五)——中斷Java程式設計
- Java併發程式設計71道面試題及答案Java程式設計面試題
- Java併發程式設計73道面試題及答案Java程式設計面試題
- Java併發程式設計40道面試題及答案——面試穩了Java程式設計面試題
- java併發程式設計系列:java併發程式設計背景知識Java程式設計
- 【Java併發程式設計】synchronized相關面試題總結Java程式設計synchronized面試題
- java 併發程式設計Java程式設計
- Java併發程式設計Java程式設計
- 穩了!Java併發程式設計71道面試題及答案Java程式設計面試題
- Java併發程式設計 - 第十一章 Java併發程式設計實踐Java程式設計
- Java併發程式設計—ThreadLocalJava程式設計thread
- Java併發程式設計:synchronizedJava程式設計synchronized
- Java併發程式設計 -- ThreadLocalJava程式設計thread
- Java併發程式設計 -- ConditionJava程式設計
- Java併發程式設計——ThreadLocalJava程式設計thread
- java-併發程式設計Java程式設計
- Java 併發程式設計解析Java程式設計
- Java併發程式設計-CASJava程式設計
- Java併發程式設計:LockJava程式設計
- Java併發程式設計---java規範與模式下的併發程式設計1.1Java程式設計模式
- Java併發程式設計之Java CAS操作Java程式設計
- Java併發程式設計:Java執行緒Java程式設計執行緒
- Java併發程式設計中的設計模式解析(一)Java程式設計設計模式
- Java併發面試題Java面試題
- Java 併發程式設計(十) -- ReentrantLock中的SyncJava程式設計ReentrantLock
- Java 併發程式設計(六) -- ThreadPoolExecutor中的WorkerJava程式設計thread
- Java 併發程式設計(八) -- AbstractQueuedSynchronizer中的NodeJava程式設計
- Java併發程式設計-鎖及併發容器Java程式設計
- Java併發程式設計之synchronizedJava程式設計synchronized
- Java併發程式設計藝術Java程式設計
- Java併發程式設計實踐Java程式設計
- Java併發程式設計基礎Java程式設計
- Java 併發程式設計 Executor 框架Java程式設計框架
- Java 併發程式設計要點Java程式設計
- Java併發程式設計:Java記憶體模型Java程式設計記憶體模型
- 【Java面試】Java設計模式面試題!Java設計模式面試題
- 【面試實戰】# 併發程式設計面試程式設計
- Java併發程式設計之執行緒篇之執行緒中斷(三)Java程式設計執行緒