[別翻了,這篇搞定] java中斷機制
技術標籤:javajava多執行緒併發程式設計thread中斷
福禍由天不由我,我命由我不由天。
一、導言
執行緒A對執行緒B發出建議:
你好,可以停止了喲~
在實際生產環境中,對於阻塞任務,可能存在一些情況導致阻塞任務取消、終止,例如: 計時器到期,I/O 完成,或者另一個執行緒的動作(釋放一個鎖,設定一個標誌,或者將一個任務放在一個工作佇列中)。這種情況下可以使用java的中斷機制來進行執行緒間通訊
。
java執行緒中斷的實現是基於一個稱為中斷狀態的內部標誌位來實現的,其中斷的含義更像是建議
,一個執行緒如何響應另一個執行緒的中斷完全取決於程式設計師: 繼續向上丟擲、封裝後丟擲、中斷狀態復原、忽略等。java庫中的許多丟擲 InterruptedException 的方法(例如 sleep)都被設計為取消當前操作並在接收到中斷時立即返回。
InterruptException
異常就像是一個宣告,宣告丟擲該異常的方法都可被中斷
,比如wait、sleep、join。異常都是由可中斷方法
自己丟擲來的,並不是直接由interrupt()
方法直接引起的。一般來說,任何通過丟擲一個 InterruptedException
來退出的方法都應該
清除中斷狀態。
二、java 中斷api
interrupt()
interrupt()
方法本質上就是通過呼叫java.lang.Thread#interrupt0
設定中斷flag為true,如下程式碼演示了該方法的使用: 另啟一個執行緒中斷了當前執行緒。
@Test
public void interruptSt () {
Thread mainThread = Thread.currentThread();
new Thread(/*將當前執行緒中斷*/mainThread::interrupt).start();
try {
//public static native void sleep(long millis) throws InterruptedException;
Thread.sleep(1_000);
} catch (InterruptedException e) {
System.out.println("main 執行緒被中斷了" );
}
/*
* 輸出: main 執行緒被中斷了
*/
}
interrupted()
和isInterrupted()
在說這兩個方法之前先說下private native boolean isInterrupted(boolean ClearInterrupted)
這個方法,interrupted()
和isInterrupted()
方法本質上都是呼叫該方法。
public boolean isInterrupted() {
// 設定this執行緒的中斷flag,不會重置中斷flag為true
return isInterrupted(false);
}
public /*靜態方法*/static boolean interrupted() {
// 設定當前執行緒的中斷flag,重置中斷flag為true
return currentThread().isInterrupted(true);
}
使用示例
@Test
public void test_Flag() {
Thread currentThread = Thread.currentThread();
currentThread.interrupt();
System.out.println("當前執行緒狀態 =" + currentThread.isInterrupted());
System.out.println("當前執行緒狀態 =" + Thread.interrupted());
System.out.println("當前執行緒狀態 =" + Thread.interrupted());
/* 輸出
當前執行緒狀態 =true
當前執行緒狀態 =true
當前執行緒狀態 =false*/
}
三、如何響應中斷?
呼叫一個可中斷的阻塞方法時需要處理受檢異常InterruptException
,一般來說最容易的方式就是繼續丟擲InterruptException
,讓呼叫方決定對中斷事件作出什麼應對。但是對於一些不能在方法頭直接新增異常宣告
的,可以catch出後再進行一些操作,例如使用Runnable
時:
一般來說當catch到中斷時,應該對中斷狀態進行還原: 呼叫Thread.currentThread().interrupt();
,除非明確自己的操作不會丟失執行緒中斷的證據,從而剝奪了上層棧的程式碼處理中斷的機會。
四、總結
- 對目標執行緒呼叫
interrupt()
方法可以請求中斷一個執行緒,目標執行緒通過檢測isInterrupted()
標誌獲取自身是否已中斷。如果目標執行緒處於阻塞狀態,該執行緒會捕獲到InterruptedException
。 - 一般來說不要catch
InterruptException
後不做處理(“生吞中斷”)。
五、參考文章
- https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
- 處理 InterruptedException
- JAVA多執行緒之中斷機制(如何處理中斷?)
- 中斷執行緒
- JAVA多執行緒之中斷機制(如何處理中斷?)
- Thread的中斷機制(interrupt)
- <<java併發程式設計實戰>>