溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解Volatile+Interrupt是停止線程優(yōu)雅的姿勢

發(fā)布時間:2021-10-18 16:54:07 來源:億速云 閱讀:151 作者:iii 欄目:web開發(fā)

本篇內(nèi)容主要講解“如何理解Volatile+Interrupt是停止線程優(yōu)雅的姿勢”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何理解Volatile+Interrupt是停止線程優(yōu)雅的姿勢”吧!

使用stop方法

調(diào)用stop方法,會讓正在運行的線程直接中止,有可能會讓一些清理性的工作得不到完成。并且stop已經(jīng)被標記為廢棄的方法,不建議使用。

正確的使用姿勢是使用兩階段終止的模式,即一個線程發(fā)送終止指令,另一個線程接收指令,并且決定自己在何時停止。

使用標志位

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循環(huán)不斷判斷,如果項目中用不到while的話,可以在關(guān)鍵節(jié)點判斷,然后退出run方法即可」

使用interrupt方法

假如我們的任務(wù)中有阻塞的邏輯,如調(diào)用了Thread.sleep方法,如何讓線程停止呢?

從線程狀態(tài)轉(zhuǎn)換圖中尋找答案

如何理解Volatile+Interrupt是停止線程優(yōu)雅的姿勢

從圖中可以看到如果想讓線程進入終止狀態(tài)的前提是這個線程處于運行狀態(tài)。當我們想要終止一個線程的時候,如果此時線程處于阻塞狀態(tài),我們?nèi)绾伟阉D(zhuǎn)換到運行狀態(tài)呢?

我們可以通過調(diào)用Thread#interrupt方法,將阻塞狀態(tài)的線程轉(zhuǎn)換到就緒狀態(tài),進入由操作系統(tǒng)調(diào)度成運行狀態(tài),即可終止。

那線程在運行狀態(tài)中調(diào)用interrupt方法,會發(fā)生什么呢?

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();     } }

依次調(diào)用start方法和stop方法,發(fā)現(xiàn)線程并沒有停止。

「其實當線程處于運行狀態(tài)時,interrupt方法只是在當前線程打了一個停止的標記,停止的邏輯需要我們自己去實現(xiàn)」

「Thread類提供了如下2個方法來判斷線程是否是中斷狀態(tài)」

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. isInterrupted

  3. interrupted

這2個方法雖然都能判斷狀態(tài),但是有細微的差別

@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的方法區(qū)別如下」

Thread#isInterrupted:測試線程是否是中斷狀態(tài),執(zhí)行后不更改狀態(tài)標志  Thread#interrupted:測試線程是否是中斷狀態(tài),執(zhí)行后將中斷標志更改為false

「所以此時我們不需要自已定義狀態(tài),直接用中斷標志即可,之前的代碼可以改為如下」

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();     } }

當線程處于阻塞狀態(tài)時,調(diào)用interrupt方法,會拋出InterruptedException,也能終止線程的執(zhí)行

「注意:發(fā)生異常時線程的中斷標志為會由true更改為false。」

所以我們有如下實現(xiàn) 當線程處于運行狀態(tài):用自己定義的標志位來退出 當線程處于阻塞狀態(tài):用拋異常的方式來退出

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();     } }

當然也可以一直用中斷標志來退出,「注意,當發(fā)生異常的時候需要重置中斷標志位」。

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是停止線程優(yōu)雅的姿勢”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI