泥瓦匠聊併發編程基礎篇:線程中斷和終止

原文:www.spring4all.comjava

1 線程中斷

1.1 什麼是線程中斷?

線程中斷是線程的標誌位屬性。而不是真正終止線程,和線程的狀態無關。線程中斷過程表示一個運行中的線程,經過其餘線程調用了該線程的 interrupt() 方法,使得該線程中斷標誌位屬性改變。git

深刻思考下,線程中斷不是去中斷了線程,偏偏是用來通知該線程應該被中斷了。具體是一個標誌位屬性,到底該線程生命週期是去終止,仍是繼續運行,由線程根據標誌位屬性自行處理。github

1.2 線程中斷操做

調用線程的 interrupt() 方法,根據線程不一樣的狀態會有不一樣的結果。web

下面新建 InterruptedThread 對象,代碼以下:spring

/**
 * 一直運行的線程,中斷狀態爲 true
 *
 * @author Jeff Lee @ bysocket.com
 * @since 2018年02月23日19:03:02
 */
public class InterruptedThread implements Runnable {

    @Override // 能夠省略
    public void run() {
        // 一直 run
        while (true) {
        }
    }

    public static void main(String[] args) throws Exception {

        Thread interruptedThread = new Thread(new InterruptedThread(), "InterruptedThread");
        interruptedThread.start();

        TimeUnit.SECONDS.sleep(2);

        interruptedThread.interrupt();
        System.out.println("InterruptedThread interrupted is " + interruptedThread.isInterrupted());

        TimeUnit.SECONDS.sleep(2);
    }
}

運行 main 函數,結果以下:編程

InterruptedThread interrupted is true

代碼詳解:安全

  • 線程一直在運行狀態,沒有中止或者阻塞等
  • 調用了 interrupt() 方法,中斷狀態置爲 true,但不會影響線程的繼續運行

另外一種狀況,新建 InterruptedException 對象,代碼以下:websocket

/**
 * 拋出 InterruptedException 的線程,中斷狀態被重置爲默認狀態 false
 *
 * @author Jeff Lee @ bysocket.com
 * @since 2018年02月23日19:03:02
 */
public class InterruptedException implements Runnable {

    @Override // 能夠省略
    public void run() {
        // 一直 sleep
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (java.lang.InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {

        Thread interruptedThread = new Thread(new InterruptedException(), "InterruptedThread");
        interruptedThread.start();

        TimeUnit.SECONDS.sleep(2);

        // 中斷被阻塞狀態(sleep、wait、join 等狀態)的線程,會拋出異常 InterruptedException
        // 在拋出異常 InterruptedException 前,JVM 會先將中斷狀態重置爲默認狀態 false
        interruptedThread.interrupt();
        System.out.println("InterruptedThread interrupted is " + interruptedThread.isInterrupted());
        TimeUnit.SECONDS.sleep(2);
    }
}

運行 main 函數,結果以下:網絡

InterruptedThread interrupted is false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)

代碼詳解:併發

  • 中斷被阻塞狀態(sleep、wait、join 等狀態)的線程,會拋出異常 InterruptedException
  • 拋出異常 InterruptedException 前,JVM 會先將中斷狀態重置爲默認狀態 false

小結下線程中斷:

  • 線程中斷,不是中止線程,只是一個線程的標誌位屬性
  • 若是線程狀態爲被阻塞狀態(sleep、wait、join 等狀態),線程狀態退出被阻塞狀態,拋出異常 InterruptedException,並重置中斷狀態爲默認狀態 false
  • 若是線程狀態爲運行狀態,線程狀態不變,繼續運行,中斷狀態置爲 true

代碼:https://github.com/JeffLi1993/java-concurrency-core-learning

2 線程終止

好比在 IDEA 中強制關閉程序,當即中止程序,不給程序釋放資源等操做,確定是不正確的。線程終止也存在相似的問題,因此須要考慮如何終止線程?

上面聊到了線程中斷,能夠利用線程中斷標誌位屬性來安全終止線程。同理也可使用 boolean 變量來控制是否須要終止線程。

新建 ,代碼以下:

/**
 * 安全終止線程
 *
 * @author Jeff Lee @ bysocket.com
 * @since 2018年02月23日19:03:02
 */
public class ThreadSafeStop {

    public static void main(String[] args) throws Exception {
        Runner one = new Runner();
        Thread countThread = new Thread(one, "CountThread");
        countThread.start();
        // 睡眠 1 秒,通知 CountThread 中斷,並終止線程
        TimeUnit.SECONDS.sleep(1);
        countThread.interrupt();

        Runner two = new Runner();
        countThread = new Thread(two,"CountThread");
        countThread.start();
        // 睡眠 1 秒,而後設置線程中止狀態,並終止線程
        TimeUnit.SECONDS.sleep(1);
        two.stopSafely();
    }

    private static class Runner implements Runnable {

        private long i;

        // 終止狀態
        private volatile boolean on = true;

        @Override
        public void run() {
            while (on && !Thread.currentThread().isInterrupted()) {
                // 線程執行具體邏輯
                i++;
            }
            System.out.println("Count i = " + i);
        }

        public void stopSafely() {
            on = false;
        }
    }
}

從上面代碼能夠看出,經過 while (on && !Thread.currentThread().isInterrupted()) 代碼來實現線程是否跳出執行邏輯,並終止。可是疑問點就來了,爲啥須要 onisInterrupted() 兩項一塊兒呢?用其中一個方式不就好了嗎?答案在下面

  • 線程成員變量 on 經過 volatile 關鍵字修飾,達到線程之間可見,從而實現線程的終止。但當線程狀態爲被阻塞狀態(sleep、wait、join 等狀態)時,對成員變量操做也阻塞,進而沒法執行安全終止線程
  • 爲了處理上面的問題,引入了 isInterrupted(); 只去解決阻塞狀態下的線程安全終止。
  • 二者結合是真的沒問題了嗎?不是的,若是是網絡 io 阻塞,好比一個 websocket 一直再等待響應,那麼直接使用底層的 close 。

3 小結

不少好友介紹,若是用 Spring 棧開發到使用線程或者線程池,那麼儘可能使用框架這塊提供的線程操做及框架提供的終止等

資料: 《Java 併發編程的藝術》

相關文章
相關標籤/搜索