線程中斷:Thread類中interrupt()、interrupted()和 isInterrupted()方法詳解


首先看看官方說明:

interrupt()方法

其作用是中斷此線程(此線程不一定是當前線程,而是指調用該方法的Thread實例所代表的線程),但實際上只是給線程設置一個中斷標志,線程仍會繼續運行

 

interrupted()方法

作用是測試當前線程是否被中斷(檢查中斷標志),返回一個boolean並清除中斷狀態,第二次再調用時中斷狀態已經被清除,將返回一個false。

 

isInterrupted()方法

 

作用是只測試此線程是否被中斷 ,不清除中斷狀態

 

 下面我們進行測試說明:

 定義一個MyThread類,繼承Thread,如下:

public class MyThread extends Thread {
    @Override
    public  void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("i="+(i+1));
        }
    }
}

在main方法中測試:

public class Do {
    public static void main(String[] args ) {
        MyThread thread=new MyThread();
        thread.start();
        thread.interrupt();
        System.out.println("第一次調用thread.isInterrupted():"+thread.isInterrupted());
        System.out.println("第二次調用thread.isInterrupted():"+thread.isInterrupted());
        System.out.println("thread是否存活:"+thread.isAlive());
    }
}

輸出如下:

  從結果可以看出調用interrupt()方法后,線程仍在繼續運行,並未停止,但已經給線程設置了中斷標志,兩個isInterrupted()方法都會輸出true,也說明isInterrupted()方法並不會清除中斷狀態。

下面我們把代碼修改一下,多加兩行調用interrupted()方法:

public class Do {
    public static void main(String[] args ) {
        MyThread thread=new MyThread();
        thread.start();
        thread.interrupt();
        System.out.println("第一次調用thread.isInterrupted():"+thread.isInterrupted());
        System.out.println("第二次調用thread.isInterrupted():"+thread.isInterrupted());
                    //測試interrupted()函數
        System.out.println("第一次調用thread.interrupted():"+thread.interrupted());
        System.out.println("第二次調用thread.interrupted():"+thread.interrupted());
        System.out.println("thread是否存活:"+thread.isAlive());
    }
}

輸出如下:

  從輸出結果看,可能會有疑惑,為什么后面兩個interrupted方法輸出的都是false,而不是預料中的一個true一個false?注意!!!這是一個坑!!!上面說到,interrupted()方法測試的是當前線程是否被中斷,當前線程!!!當前線程!!!,這里當前線程是main線程,而thread.interrupt()中斷的是thread線程,這里的此線程就是thread線程。所以當前線程main從未被中斷過,盡管interrupted()方法是以thread.interrupted()的形式被調用,但它檢測的仍然是main線程而不是檢測thread線程,所以thread.interrupted()在這里相當於main.interrupted()。對於這點,下面我們再修改進行測試。

Thread.currentThread()函數可以獲取當前線程,下面代碼中獲取的是main線程

public class Do {
    public static void main(String[] args ) throws InterruptedException {
        Thread.currentThread().interrupt();
        System.out.println("第一次調用Thread.currentThread().interrupt():"
                +Thread.currentThread().isInterrupted());
        System.out.println("第一次調用thread.interrupted():"
                +Thread.currentThread().interrupted());
        System.out.println("第二次調用thread.interrupted():"
                +Thread.currentThread().interrupted());
    }
}

  這里都是針對當前線程在操作,如果interrupted()方法有檢測中斷並清除中斷狀態的作用,預料中的輸出應該是true-true-false,實際輸出如下:

 

結果證明猜想是正確的。

  若果想要是實現調用interrupt()方法真正的終止線程,則可以在線程的run方法中做處理即可,比如直接跳出run()方法使線程結束,視具體情況而定,下面是一個例子。

修改MyThread類:

public class MyThread extends Thread {
    @Override
    public  void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("i="+(i+1));
            if(this.isInterrupted()){
                System.out.println("通過this.isInterrupted()檢測到中斷");
                System.out.println("第一個interrupted()"+this.interrupted());
                System.out.println("第二個interrupted()"+this.interrupted());
                break;
            }
        }
        System.out.println("因為檢測到中斷,所以跳出循環,線程到這里結束,因為后面沒有內容了");
    }
}

測試MyThread:

public class Do {
    public static void main(String[] args ) throws InterruptedException {
        MyThread myThread=new MyThread();
        myThread.start();
        myThread.interrupt();
        //sleep等待一秒,等myThread運行完
        Thread.currentThread().sleep(1000);
        System.out.println("myThread線程是否存活:"+myThread.isAlive());
    }
}

結果:

總結

  關於這三個方法,interrupt()是給線程設置中斷標志;

          interrupted()是檢測中斷並清除中斷狀態;

          isInterrupted()只檢測中斷。

  還有重要的一點就是interrupted()作用於當前線程,interrupt()和isInterrupted()作用於此線程,即代碼中調用此方法的實例所代表的線程。

 -------------------------------------------對線程中斷的理解-------------------------------------------

首先,一個線程不應該由其他線程來強制中斷或停止,而是應該由線程自己自行停止。
所以,Thread.stop, Thread.suspend, Thread.resume 都已經被廢棄了。
而 Thread.interrupt 的作用其實也不是中斷線程,而是「通知線程應該中斷了」,
具體到底中斷還是繼續運行,應該由被通知的線程自己處理。

具體來說,當對一個線程,調用 interrupt() 時,
① 如果線程處於被阻塞狀態(例如處於sleep, wait, join 等狀態),那么線程將立即退出被阻塞狀態,並拋出一個InterruptedException異常。僅此而已。
② 如果線程處於正常活動狀態,那么會將該線程的中斷標志設置為 true,僅此而已。被設置中斷標志的線程將繼續正常運行,不受影響。

interrupt() 並不能真正的中斷線程,需要被調用的線程自己進行配合才行。
也就是說,一個線程如果有被中斷的需求,那么就可以這樣做。
① 在正常運行任務時,經常檢查本線程的中斷標志位,如果被設置了中斷標志就自行停止線程。
② 在調用阻塞方法時正確處理InterruptedException異常。(例如,catch異常后就結束線程。)
Thread thread = new Thread(() -> {
    while (!Thread.interrupted()) {
        // do more work.
    }
});
thread.start();

// 一段時間以后
thread.interrupt();
具體到你的問題,Thread.interrupted()清除標志位是為了下次繼續檢測標志位。
如果一個線程被設置中斷標志后,選擇結束線程那么自然不存在下次的問題,
而如果一個線程被設置中斷標識后,進行了一些處理后選擇繼續進行任務,
而且這個任務也是需要被中斷的,那么當然需要清除標志位了。

 例子:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // sleepThread睡眠1000ms
        final Thread sleepThread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                super.run();
            }
        };
        // busyThread一直執行死循環
        Thread busyThread = new Thread() {
            @Override
            public void run() {
                while (true);
            }
        };
        sleepThread.start();
        busyThread.start();
        sleepThread.interrupt(); // 改變中斷狀態標志位
        busyThread.interrupt();
        System.out.println(busyThread.isInterrupted());
        while (sleepThread.isInterrupted()); // 一直死循環等待該中斷標志位被改變才繼續執行下面的代碼
        System.out.println("sleepThread isInterrupted: " + sleepThread.isInterrupted());
        System.out.println("busyThread isInterrupted: " + busyThread.isInterrupted());
    }

}

輸出:

 

 

 出處:

  https://blog.csdn.net/qq_39682377/article/details/81449451

  https://www.zhihu.com/question/41048032

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM