爲何建議不使用 stop 方法中止線程?

保存好你作過的全部源文件——那是你最好的積累之一。安全

線程啓動完畢後,在運行時可能須要終止,Java提供的終止方法只有一個stop,可是我不建議使用這個方法,由於它有如下三個問題:多線程

(1)stop方法是過期的從Java編碼規則來講,已通過時的方法不建議採用。ide

(2)stop方法會致使代碼邏輯不完整stop方法是一種「惡意」的中斷,一旦執行stop方法,即終止當前正在運行的線程,無論線程邏輯是否完整,這是很是危險的。看以下的代碼:編碼

public static void main(String[] args) throws Exception {
    // 子線程
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                // 子線程休眠一秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // 異常處理
            }
        }
    };
    // 啓動線程
    thread.start();
    // 主線程休眠一秒
    Thread.sleep(1000);
    // 子線程中止
    thread.stop();
}

這段代碼的邏輯是這樣的:子線程是一個匿名內部類,它的run方法在執行時會休眠1秒鐘,而後再執行後續的邏輯,而主線程則是休眠0.1秒後終止子線程的運行,也就是說,JVM在執行thread.stop()時,子線程還在執行sleep(1000),此時stop方法會清除棧內信息,結束該線程,這也就致使了run方法的邏輯不完整,輸出語句println表明的是一段邏輯,可能很是重要,好比子線程的主邏輯、資源回收、情景初始化等,可是由於stop線程了,這些就都再也不執行,因而就產生了業務邏輯不完整的狀況。線程

這是極度危險的,由於咱們不知道子線程會在何時被終止,stop連基本的邏輯完整性都沒法保證。並且此種操做也是很是隱蔽的,子線程執行到何處會被關閉很難定位,這爲之後的維護帶來了不少麻煩。code

(3)stop方法會破壞原子邏輯多線程爲了解決共享資源搶佔的問題,使用了鎖概念,避免資源不一樣步,可是正所以緣由,stop方法卻會帶來更大的麻煩:它會丟棄全部的鎖,致使原子邏輯受損。例若有這樣一段程序:接口

class MultiThread implements Runnable {
    int a = 0;

    @Override
    public void run() {
        // 同步代碼塊,保證原子操做
        synchronized ("") {
            a++; // 自增
            try {
                // 線程休眠0.1秒
                Thread.sleep(100);
            } catah(InterruptedException e) {
                e.printStackTrace();
            }
            a--; // 自減
            String tn = Thread.currentThread().getName();
            System.out.println(tn + ":a=" + a);
        }
    }
}

MultiThread實現了Runnable接口,具有多線程能力,其中run方法中加上了synchronized代碼塊,表示內部是原子邏輯,它會先自增而後再自減小,按照synchronized同步代碼塊的規則來處理,此時不管啓動多少個線程,打印出來的結果都應該是a=0,可是若是有一個正在執行的線程被stop,就會破壞這種原子邏輯,代碼以下:資源

public static void main(String[] args) {
    MultiThread thread = new MultiThread();
    Thread thread1 = new Thread(thread);
    // 啓動thread1線程
    thread1.start();
    for (int i = 0; i < 5; i++) {
        new Thread(thread).start();
    }
    // 中止thread1線程
    thread1.stop();
}

首先要說明的是全部線程共享了一個MultiThread的實例變量t,其次因爲在run方法中加入了同步代碼塊,因此只能有一個線程進入到synchronized塊中。此段代碼的執行順序以下:get

1)線程t1啓動,並執行run方法,因爲沒有其餘線程持同步代碼塊的鎖,因此t1線程執行自加後執行到sleep方法即開始休眠,此時a=1。同步

2)JVM又啓動了5個線程,也同時運行run方法,因爲synchronized關鍵字的阻塞做用,這5個線程不能執行自增和自減操做,等待t1線程鎖釋放。

3)主線程執行了t1.stop方法,終止了t1線程,注意,因爲a變量是全部線程共享的,因此其餘5個線程得到的a變量也是1。

4)其餘5個線程依次得到CPU執行機會,打印出a值。

分析了這麼多,相信讀者也明白了輸出的結果,結果以下:

Thread-5:a=1
Thread-4:a=1
Thread-3:a=1
Thread-2:a=1
Thread-1:a=1

本來指望synchronized同步代碼塊中的邏輯都是原子邏輯,不受外界線程的干擾,可是結果卻出現原子邏輯被破壞的狀況,這也是stop方法被廢棄的一個重要緣由:破壞了原子邏輯。

既然終止一個線程不能使用stop方法,那怎樣才能終止一個正在運行的線程呢?答案也很簡單,使用自定義的標誌位決定線程的執行狀況,代碼以下:

class SafeStopThread extends Thread {
    // 此變量必須加上volatile
    private volatile boolean stop = false;

    @Override
    public void run() {
        // 判斷線程體是否運行
        while (stop) {
            // Do Something
        }
    }
    // 線程終止
    public void terminate() {
        stop = true;
    }
}

這是很簡單的辦法,在線程體中判斷是否須要中止運行,便可保證線程體的邏輯完整性,並且也不會破壞原子邏輯。可能有讀者對Java API比較熟悉,因而提出疑問:Thread不是還提供了interrupt中斷線程的方法嗎?這個方法可不是過期方法,那可使用嗎?它能夠終止一個線程嗎?

很是好的問題,interrupt,名字看上去很像是終止一個線程的方法,可是我能夠很明確地告訴你,它不是,它不能終止一個正在執行着的線程,它只是修改中斷標誌而已,例以下面一段代碼:

public static void main(String[] args) {
    Thread thread = new Thread() {
        public void run() {
            // 線程一直運行
            while (true) {
                System.out.println("Running...");
            }
        }
    };
    // 啓動thread線程
    thread.start();
    // 中斷thread線程
    thread.interrupt();
}

執行這段代碼,你會發現一直有Running在輸出,永遠不會中止,彷佛執行了interrupt沒有任何變化,那是由於interrupt方法不能終止一個線程狀態,它只會改變中斷標誌位(若是在t1.interrupt()先後輸出t1.isInterrupted()則會發現分別輸出了false和true),若是須要終止該線程,還須要自行進行判斷,例如咱們可使用interrupt編寫出更加簡潔、安全的終止線程代碼:

class SafeStopThread extends Thread {
    @Override
    public void run() {
        // 判斷線程體是否運行
        while (!isInterrupted()) {
            // Do Something
        }
    }
}

總之,若是指望終止一個正在運行的線程,則不能使用已通過時的stop方法,須要自行編碼實現,如此便可保證原子邏輯不被破壞,代碼邏輯不會出現異常。固然,若是咱們使用的是線程池(好比ThreadPoolExecutor類),那麼能夠經過shutdown方法逐步關閉池中的線程,它採用的是比較溫和、安全的關閉線程方法,徹底不會產生相似stop方法的弊端。

相關文章
相關標籤/搜索