1. 程式人生 > 其它 >[別翻了,這篇搞定] java中斷機制

[別翻了,這篇搞定] 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時:

image-20210102214450199

一般來說當catch到中斷時,應該對中斷狀態進行還原: 呼叫Thread.currentThread().interrupt();,除非明確自己的操作不會丟失執行緒中斷的證據,從而剝奪了上層棧的程式碼處理中斷的機會。

四、總結

  1. 對目標執行緒呼叫interrupt()方法可以請求中斷一個執行緒,目標執行緒通過檢測isInterrupted()標誌獲取自身是否已中斷。如果目標執行緒處於阻塞狀態,該執行緒會捕獲到InterruptedException
  2. 一般來說不要catchInterruptException後不做處理(“生吞中斷”)。

五、參考文章

  1. https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
  2. 處理 InterruptedException
  3. JAVA多執行緒之中斷機制(如何處理中斷?)
  4. 中斷執行緒
  5. JAVA多執行緒之中斷機制(如何處理中斷?)
  6. Thread的中斷機制(interrupt)
  7. <<java併發程式設計實戰>>

在這裡插入圖片描述