1. 程式人生 > >【多執行緒】Thread.interrupted()與thread.isInterrupted()的區別

【多執行緒】Thread.interrupted()與thread.isInterrupted()的區別

在Java的執行緒基本操作方法中,有兩種方式獲取當前執行緒的isInterrupt屬性。一種是物件方法thread.isInterrupted(),另一種是Thread類的靜態方法Thread.interrupted()。這兩個方法看似相同,實際上是有區別的,我們來看看Java的Thread類的這部分原始碼:

public
class Thread implements Runnable {
    ......

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

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

    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);

    ......
}

可以看到,物件方法的thread.isInterrupted()和靜態方法的Thread.interrupted()都是呼叫的JNI底層的isInterrupted()方法。但是區別在於這個ClearInterrupted引數,前者傳入的false,後者傳入的是true。相信各位讀者都已經猜出其中的含義了,ClearInterrupted引數向作業系統層指明是否在獲取狀態後將當前執行緒的isInterrupt屬性重置為(或者叫恢復,或者叫清除)false。

這就意味著當某個執行緒的isInterrupt屬性成功被置為true後,如果您使用物件方法thread.isInterrupted()獲取值,無論您獲取多少次得到的返回值都是true;但是如果您使用靜態方法Thread.interrupted()獲取值,那麼只有第一次獲取的結果是true,隨後執行緒的isInterrupt屬性將被恢復成false,後續無論使用Thread.interrupted()呼叫還是使用thread.isInterrupted()呼叫,獲取的結果都是false

=====================================================================

呼叫Thread.interrupt()方法並不能真正停止執行緒,只是在當前執行緒做了一箇中斷的狀態標誌。

public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            super.run();
            System.out.println("i="+(i+1));
        }
    }

}
public class Runner {
    public static void main(String[] args) {

            MyThread myThread = new MyThread();
            myThread.start();
            myThread.interrupt();
            System.out.println("第一次呼叫myThread.isInterrupted(),返回值:"+myThread.isInterrupted());
            System.out.println("第二次呼叫myThread.isInterrupted(),返回值:"+myThread.isInterrupted());
            System.out.println("===========end=============");
    }

}

上面我們建立了一個MyThread執行緒,然後Runner類中,執行main方法,建立MyThread的例項,啟動執行緒,然後呼叫myThread.interrupt();  打印出資訊:

i=1  第一次呼叫myThread.isInterrupted(),返回值:true  i=2  第二次呼叫myThread.isInterrupted(),返回值:true  i=3  ==========end==============  i=4  i=5  i=6  i=7  i=8  i=9  i=10  i=11  i=12  i=13  i=14

從列印資訊可以看出,雖然呼叫了myThread.interrupt()方法,但是MyThread並沒有立即中斷執行。這裡我們兩次呼叫myThread.isInterrupted(),返回值都是true。  我們對Runner方法坐下修改,改成兩次呼叫myThread.interrupted()。  程式碼如下:

public class Runner {
    public static void main(String[] args) {

            MyThread myThread = new MyThread();
            myThread.start();
            myThread.interrupt();
            System.out.println("第一次呼叫myThread.interrupted(),返回值:"+myThread.interrupted());
            System.out.println("第二次呼叫myThread.interrupted(),返回值:"+myThread.interrupted());
            System.out.println("============end===================");
    }

}

列印資訊如下:

第一次呼叫myThread.interrupted(),返回值:false  i=1  第二次呼叫myThread.interrupted(),返回值:false  i=2  ===========end=================  i=3  i=4  i=5  i=6

雖然執行緒依然沒有被中斷,但是呼叫myThread.interrupted()是,返回都是false。難度是MyThread並沒有中斷狀態嗎?

再看一下程式碼:

public class Runner {
    public static void main(String[] args) {

            Thread.currentThread().interrupt();
            System.out.println("第一次呼叫Thread.interrupted(),返回值:"+Thread.interrupted());
            System.out.println("第二次呼叫Thread.interrupted(),返回值:"+Thread.interrupted());
            System.out.println("=================end===============================");
    }

}

列印資訊如下:

第一次呼叫Thread.interrupted(),返回值:true  第二次呼叫Thread.interrupted(),返回值:false  ========end=======

以上程式碼是對當前執行緒,即main方法執行的執行緒,呼叫interrunt方法。第一次呼叫Thread.interrupted()返回值是true,說明當前執行緒已經被標記了中斷狀態,那麼為什麼第二次呼叫Thread.interrupted()返回值卻是false呢?

這裡需要引出官方文件對Thread.interrupted()的定義:

測試當前執行緒是否已經中斷,執行緒的中斷狀態也是由該方法清除。

也就是說,如果連續兩次呼叫該方法,那麼第一次呼叫時,如果當前執行緒已經處於中斷狀態,那麼該方法會返回true,同時清除當前執行緒被標記的中斷狀態。第二次呼叫時,(第二次呼叫之前,沒有再次呼叫Thread.currentThread().interrupt();)就會返回false了。

總結

  1. 呼叫執行緒的interrupt方法,並不能真正中斷執行緒,只是給執行緒做了中斷狀態的標誌
  2. Thread.interrupted():測試當前執行緒是否處於中斷狀態。執行後將中斷狀態標誌為false
  3. Thread.isInterrupte(): 測試執行緒Thread物件是否已經處於中斷狀態。但不具有清除功能