您好,登錄后才能下訂單哦!
本篇內容主要講解“如何理解Volatile+Interrupt是停止線程優雅的姿勢”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何理解Volatile+Interrupt是停止線程優雅的姿勢”吧!
使用stop方法
調用stop方法,會讓正在運行的線程直接中止,有可能會讓一些清理性的工作得不到完成。并且stop已經被標記為廢棄的方法,不建議使用。
正確的使用姿勢是使用兩階段終止的模式,即一個線程發送終止指令,另一個線程接收指令,并且決定自己在何時停止。
使用標志位
public class RunTask { private volatile boolean stopFlag; private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!stopFlag) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { stopFlag = true; } }
「stopFlag上加volatile是保證可見性。我這個例子用了while循環不斷判斷,如果項目中用不到while的話,可以在關鍵節點判斷,然后退出run方法即可」
使用interrupt方法
假如我們的任務中有阻塞的邏輯,如調用了Thread.sleep方法,如何讓線程停止呢?
從線程狀態轉換圖中尋找答案
從圖中可以看到如果想讓線程進入終止狀態的前提是這個線程處于運行狀態。當我們想要終止一個線程的時候,如果此時線程處于阻塞狀態,我們如何把它轉換到運行狀態呢?
我們可以通過調用Thread#interrupt方法,將阻塞狀態的線程轉換到就緒狀態,進入由操作系統調度成運行狀態,即可終止。
那線程在運行狀態中調用interrupt方法,會發生什么呢?
public class RunTaskCase1 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (true) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
依次調用start方法和stop方法,發現線程并沒有停止。
「其實當線程處于運行狀態時,interrupt方法只是在當前線程打了一個停止的標記,停止的邏輯需要我們自己去實現」
「Thread類提供了如下2個方法來判斷線程是否是中斷狀態」
鴻蒙官方戰略合作共建——HarmonyOS技術社區
isInterrupted
interrupted
這2個方法雖然都能判斷狀態,但是有細微的差別
@Test public void testInterrupt() throws InterruptedException { Thread thread = new Thread(() -> { while (true) {} }); thread.start(); TimeUnit.MICROSECONDS.sleep(100); thread.interrupt(); // true System.out.println(thread.isInterrupted()); // true System.out.println(thread.isInterrupted()); // true System.out.println(thread.isInterrupted()); }
@Test public void testInterrupt2() { Thread.currentThread().interrupt(); // true System.out.println(Thread.interrupted()); // false System.out.println(Thread.interrupted()); // false System.out.println(Thread.interrupted()); }
「isInterrupted和interrupted的方法區別如下」
Thread#isInterrupted:測試線程是否是中斷狀態,執行后不更改狀態標志 Thread#interrupted:測試線程是否是中斷狀態,執行后將中斷標志更改為false
「所以此時我們不需要自已定義狀態,直接用中斷標志即可,之前的代碼可以改為如下」
public class RunTaskCase2 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { System.out.println("doSomething"); } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
當線程處于阻塞狀態時,調用interrupt方法,會拋出InterruptedException,也能終止線程的執行
「注意:發生異常時線程的中斷標志為會由true更改為false。」
所以我們有如下實現 當線程處于運行狀態:用自己定義的標志位來退出 當線程處于阻塞狀態:用拋異常的方式來退出
public class RunTaskCase3 { private volatile boolean stopFlag; private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (stopFlag) { try { System.out.println("doSomething"); TimeUnit.MICROSECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }); taskThread.start(); } public void stop() { stopFlag = true; taskThread.interrupt(); } }
當然也可以一直用中斷標志來退出,「注意,當發生異常的時候需要重置中斷標志位」。
public class RunTaskCase4 { private Thread taskThread; public void start() { taskThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("doSomething"); TimeUnit.MICROSECONDS.sleep(100); } catch (InterruptedException e) { // 重置中斷標志位為true Thread.currentThread().interrupt(); e.printStackTrace(); } } }); taskThread.start(); } public void stop() { taskThread.interrupt(); } }
到此,相信大家對“如何理解Volatile+Interrupt是停止線程優雅的姿勢”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。