您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Java線程中斷機制的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Java線程中斷機制的示例分析”這篇文章吧。
線程中斷機制提供了一種方法,用于將線程從阻塞等待中喚醒,嘗試打斷目標線程的現有處理流程,使之響應新的命令。
線程中斷機制提供了一種方法,有兩種常見用途:
將線程從阻塞等待中喚醒,并作出相應的“受控中斷”處理。
嘗試告知目標線程:請打斷現有處理流程,響應新的命令。
以第一種用途為例,請看以下代碼:
synchronized (lock) { try { while (!check()) { lock.wait(1000); } } catch (InterruptedException e) { e.printStackTrace(); } }
這段代碼使用了 Java 提供的 wait/notify 機制,線程執行 lock.wait() 會阻塞,有三種情況使線程恢復運行。
1、超時 1000ms 結束,正常執行下一句代碼。
2、另一個線程執行下述代碼主動喚醒
synchronized (lock) { lock.notifyAll(); // or lock.notify(); }
這也會正常執行下一句代碼。
3、另一個線程要求等待的線程“中斷”
// 拿到等待中的線程的引用 Thread a; a.interrupt();
被“中斷”的線程 a,會在 lock.wait() 處拋出 InterruptedException 異常。
綜上所述,你可以認為 object.wait() 內部在做這些事:
boolean checkTimeout = timeout > 0; Thread current = Thread.currentThread(); lock.addWaiter(current); while (!current.isNotified()) { if (current.isInterrupted()) { current.clearInterrupted(); throw new InterruptedException(); } if (checkTimeout) { if (timeout == 0) break; timeout--; } }
這不完全準確,因為 wait 不使用這種“忙輪詢”的方式做檢查,但關于標志位的判斷邏輯是正確的。
讓我們從上文所述的“手動發出中斷”這一操作開始探究
// sun.nio.ch.Interruptible public interface Interruptible { void interrupt(Thread var1); } // java.lang.Thread private volatile Interruptible blocker; private final Object blockerLock = new Object(); public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); b.interrupt(this); return; } } interrupt0(); } // Just to set the interrupt flag private native void interrupt0();
能夠看出,thread.interrupt() 先判斷權限,然后實際調用 interrupt0() 設置線程的中斷標志,如果當前線程有 nio 的 Interruptible 那么還會回調它。
注意,interrupt0() 只是設置了線程的中斷標志。
當一個線程并不阻塞,沒有在 object.wait(), thread.join(), Thread.sleep() 等不受 Java 程序邏輯控制的區域時,那么會發生什么事情?答案是不會發生任何事情,線程是否被打斷只能通過主動地檢查中斷標志得知。
怎么檢查?Thread 暴露了兩個接口,Thread.interrupted() 和 thread.isInterrupted()。
// java.lang.Thread public static boolean interrupted() { return currentThread().isInterrupted(true); } public boolean isInterrupted() { return isInterrupted(false); } private native boolean isInterrupted(boolean clearInterrupted);
能夠看出,兩者都是依靠內部的 isInterrupted(boolean),而它會返回線程是否被打斷,并根據需要清空中斷標志。
當一個函數調用會發生阻塞,Java 庫函數在阻塞的源頭簽名里標記 throws InterruptedException,并要求編寫 try catch 處理中斷。
當線程發生了阻塞,就像上文所述,Java 檢查到中斷標志,先將其清除,然后拋出 InterruptedException。
// java.lang.Object public final void wait() throws InterruptedException { wait(0); } public final native void wait(long timeout) throws InterruptedException;
如果一個線程收到 InterruptedException,之后仍然執行了會引發阻塞的代碼,它將像“沒事人”一樣繼續阻塞住。因為 Java 在內部將中斷標志清除了!
我們常見地編寫以下三類處理 InterruptedException 的代碼:
將 InterruptedException 交由上層處理。
public void foo() throws InterruptedException { synchronized (lock) { lock.wait(); } }
遇到 InterruptedException 重設中斷標志位。
try { synchronized (lock) { lock.wait(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); //break; }
先忙完,再重新拋出 InterruptedException。
public void bar() throws InterruptedException { InterruptedException ie = null; boolean done = false; while (!done) { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { ie = e; continue; } } done = true; } if (ie != null) { throw ie; } }
如果一個線程無視中斷標志和 InterruptedException,它仍然能夠跑的很好。但這與我們設計多線程的初衷是違背的,我們希望線程之間是和諧的有序協作以實現特定功能,因此受控線程應當對中斷作出響應。
以上是“Java線程中斷機制的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。