安全優雅地停止線程

首先,先拋出一個問題,該如何安全而優雅地停止線程?

這道問題的背後,可以很小,小到只是簡單終止一個Thread線程,也可以很大,大到例如Dubbo應用的優雅下線......它們其實都有一個共同之處,即非一刀斷式地暴力停止某個進程或者線程,而是能夠實現在終止過程中,有機會去清理資源,跑完剩餘的任務,最後沒有任何資源在運行了,才做最後結束,這纔算安全而優雅地停止。

在Java多線程當中,停止線程的方法,其中,有一個已經過期而不建議使用的方式stop(),它停止線程的方式比較簡單粗暴,不保證線程的資源正常釋放就直接停止了,也就意味着,可能還有線程正在跑,沒有運行完成,就直接終結了,這可能會導致程序出現不確定的狀態,即死鎖狀態。

以stop方式終結線程的方法已經過期,即不再建議使用。

那麼,可有其他方式來優雅地結束線程運行嗎?

這裏,可以通過interrupt()方法間接實現。

爲什麼說是簡接實現呢?

因爲線程執行interrupt()方法並不會直接就終止線程。

接下來,就簡單分析一下,interrupt()是如何實現安全而優雅地終止線程的。

首先,當執行線程的interrupt()方法後,就會給該線程打上一個中斷的標識屬性,該標識屬性原本是false的,但被打上中斷標識後,就會變成true了,這裏有點類似volatitle變量的可見性玩法,通過這樣的可見性變量,我們就可以設置某種狀態,當滿足該狀態時,就可以跳出程序,提前結束。

可以通過isInterrupted()方法獲取到中斷標識屬性的狀態值,若是true,表示該線程已經被打上中斷標識,那麼,就可以先清理完資源後,再結束該線程。

然而,需要注意一點是,這裏有一個類似的靜態方法,Thread.interrupted(),該方法也可以獲取到線程中斷狀態,但遺憾的是,這個interrupted方法在判斷一次線程是否中斷後,就會立即對該線程的中斷狀態復位,即恢復線程到非中斷的狀態。除此之外,聲明拋出InterruptedException的方法,在拋出異常前,也會通過虛擬機將該線程的中斷標識狀態清除,然後再拋出異常,這時再調用isInterrupted()方法返回的是false。

這裏以代碼驗證一下——

public static void main(String[] args) throws InterruptedException {
    Runner one = new Runner();
    Thread countThread = new Thread(one,"CountThread");
    //啓動線程
    countThread.start();
    //沉默一秒,先讓線程CountThread執行1秒
    TimeUnit.SECONDS.sleep(1);
    //通過interrupt()方法對線程countThread設置中斷標識
    countThread.interrupt();
}

private static class Runner implements Runnable {
    private long i;
    private volatile boolean on = true;
    @Override
    public void run() {
        //當countThread線程標識中斷時,Thread.currentThread().isInterrupted()返回的是true,即可結束該線程,同時,停止資源i++的繼續運行
        while (!Thread.currentThread().isInterrupted()){
            i++;
        }
        System.out.println("Count i = " + i);
    }
}

前邊提到過,interrupt()標識中斷位的玩法,很類似volatitle變量的可見性,反過來,volatitle某種程度上也可以替代interrupt()來判斷線程是否需要中斷,類似代碼如下——

public static void main(String[] args) throws InterruptedException {
    Runner two = new Runner();
    Thread countThread = new Thread(two,"CountThread");
    countThread.start();
    //睡眠1秒
    TimeUnit.SECONDS.sleep(1);
    two.cancel();

}

private static class Runner implements Runnable {
    private long i;
    private volatile boolean on = true;
    @Override
    public void run() {
        while (on){
            i++;
        }
        System.out.println("Count i = " + i);
    }

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

參考《Java併發編程的藝術》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章