1. 程式人生 > >深入理解Java中停止執行緒

深入理解Java中停止執行緒

一.停止執行緒會帶來什麼?

對於單執行緒中,停止單執行緒就是直接使用關鍵字return或者break,但是在停止多執行緒時是讓執行緒在完成任務前去開啟另外一條執行緒,必須放棄當前任務,而這個過程是不可預測,所以必須去做好防備。

二.認識停止執行緒的幾個方法

 2.1三個被棄用的方法

 stop()、suspend()、resume()。

 stop()方法被棄用的原因:無論執行緒執行到了什麼位置,一旦被stop就會被馬上強制中斷,並且釋放執行緒所有持有鎖物件,根本就沒有安全性。

 suspend()和resume()這一對爛兄爛弟,因為只有其他執行緒呼叫resume這個方法時他才會釋放suspend這個方法的鎖,這樣就極易造成死鎖。

 2.2三個名字差不多的方法

 interrupt()中斷執行緒、interrupted()判斷當前執行緒是否停止、isInterrupted()判斷執行緒是否停止。

 首先來介紹一下其中兩個名字最相近的:interrupted()、isInterrupted()方法,這兩個方法是用來測試執行緒是否被中斷的。

 來看一下原碼:

isInterrupted():

    public boolean isInterrupted() {
        return isInterrupted(false);
    }

 

 interrupted():

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

可以明顯看出interrupted()方法是靜態的,而isInterrupted()是非靜態的,但都是返回執行緒是否被中斷。

下面我們來做一個測試,程式碼如下:


    public class Is_Interrupt extends Thread{
        @Override
        public void run(){
            for(int i=0;i<1000;i++){
                System.out.println("當前i的值為:"+i);
            }
        }
        public static void main(String[] args) {
            Is_Interrupt is_interrupt=new Is_Interrupt();
            is_interrupt.start();
            is_interrupt.interrupt();//中斷執行緒
            System.out.println("執行緒是否已經暫停?"+is_interrupt.interrupted());
        }
    }



 輸出結果為:


發現執行緒沒有停止。

但是這裡面還有一個執行緒就是main執行緒,而interrupted()返回的就是當前執行緒的中斷狀態,那麼執行這個方法的就是main執行緒,而main執行緒此時當然沒有中斷。

我們將interrupted()方法改為isInterrupted()試試效果,程式碼如下:


    public class Is_Interrupt extends Thread{
        @Override
        public void run(){
            for(int i=0;i<1000;i++){
                System.out.println("當前i的值為:"+i);
            }
        }
        public static void main(String[] args) {
            Is_Interrupt is_interrupt=new Is_Interrupt();
            is_interrupt.start();
            is_interrupt.interrupt();//中斷執行緒
            System.out.println("執行緒是否已經暫停?"+is_interrupt.isInterrupted());
        }
    }



結果如下:


說明執行緒是已經停止了的,只不過我們使用錯了一個方法而已判斷成了main執行緒的狀態。

總結:isInterrupted方法是返回呼叫物件的中斷狀態,而靜態方法interrupted是返回當前執行緒的中斷狀態。

既然瞭解了這個誤區以後我們再來看看下面的程式碼:


public class InterruptText extends Thread{
    public static void main(String[] args) {
        System.out.println("main執行緒啟動!");
        System.out.println( Thread.interrupted());//判斷當前執行緒是否中斷
        System.out.println(currentThread().isInterrupted());//通過currentThread().isInterrupted()同樣也可以達到相同的目的,在單執行緒中
    }
}



輸出:

這個是沒有問題的。

那麼我們多次呼叫這個interrupted方法呢?


public class InterruptText extends Thread{
    public static void main(String[] args) {
        System.out.println("main執行緒啟動!");
        currentThread().interrupt();//中斷main執行緒
        System.out.println( Thread.interrupted());//判斷當前main執行緒是否中斷
        System.out.println( Thread.interrupted());//再一次判斷當main前執行緒是否中斷
    }
}



 結果:

按照常理應該兩次返回ture,但是為什麼變成了第二次變成了false了呢?

其實interrupted就是在清除狀態,你兩次呼叫當然會將true變成flase但是他還是中斷狀態,但是isInterrupted是不清除的。

interrupt()方法:中斷執行緒

三.停止執行緒

3.1通過異常來暫停執行緒

 首先來看一段程式碼:


public class InterruptText extends Thread{
    @Override
    public void run(){
        try {
            for (int i = 0; i < 100000; i++) {
                if (currentThread().isInterrupted()) {//如果執行緒中斷
                    throw new InterruptedException();//丟擲異常
                } else {
                    System.out.println(i);
                }
            }
            System.out.println("執行緒沒有終止");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception {
        InterruptText interruptText=new InterruptText();
        interruptText.start();
        Thread.sleep(100);
        interruptText.interrupt();
    }
}



 結果:


異常停止方法的策略就是:在遇到中斷時,丟擲異常,撲捉異常。

3.2在睡眠中中斷執行緒

 程式碼如下:


public class InterruptText2 extends Thread {
    @Override
    public void run(){
        try {
            Thread.sleep(10000);//執行緒睡眠
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        InterruptText2 interruptText2=new InterruptText2();
        interruptText2.start();//開啟執行緒,但是執行緒處於睡眠狀態
        interruptText2.interrupt();//在睡眠狀態中斷執行緒
        
    }
}



 結果為:


3.3執行緒讓步

 方法:yield(),當前執行緒放棄所有的資源,去執行其他的任務。但是放棄資源的時間不可以預判的。

3.4守護執行緒

 守護執行緒的定義:守護執行緒是一種特殊的執行緒,區別於非守護執行緒,當程式中不存在非守護執行緒時,守護執行緒退出,程式退出。

設定守護執行緒:setDaemon(),引數為ture則該執行緒為守護執行緒。

在此我向大家推薦一個架構學習交流群。交流學習群號874811168 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化、分散式架構等這些成為架構