1. 程式人生 > >總結一下interrupt,interrupted isInterrupted的區別

總結一下interrupt,interrupted isInterrupted的區別

interrupt()的作用是中斷本執行緒。
本執行緒中斷自己是被允許的;其它執行緒呼叫本執行緒的interrupt()方法時,會通過checkAccess()檢查許可權。這有可能丟擲SecurityException異常。
如果本執行緒是處於阻塞狀態:呼叫執行緒的wait(), wait(long)或wait(long, int)會讓它進入等待(阻塞)狀態,或者呼叫執行緒的join(), join(long), join(long, int), sleep(long), sleep(long, int)也會讓它進入阻塞狀態。若執行緒在阻塞狀態時,呼叫了它的interrupt()

方法,那麼它的“中斷狀態”會被清除並且會收到一個InterruptedException異常。例如,執行緒通過wait()進入阻塞狀態,此時通過interrupt()中斷該執行緒;呼叫interrupt()會立即將執行緒的中斷標記設為“true”,但是由於執行緒處於阻塞狀態,所以該“中斷標記”會立即被清除為“false”,同時,會產生一個InterruptedException的異常。
如果執行緒被阻塞在一個Selector選擇器中,那麼通過interrupt()中斷它時;執行緒的中斷標記會被設定為true,並且它會立即從選擇操作中返回。
如果不屬於前面所說的情況,那麼通過interrupt()中斷執行緒時,它的中斷標記會被設定為“true”。
中斷一個“已終止的執行緒”不會產生任何操作。


interrupted()isInterrupted()的區別
interrupted() 和 isInterrupted()都能夠用於檢測物件的“中斷標記”。
區別是,interrupted()除了返回中斷標記之外,它還會清除中斷標記(即將中斷標記設為false);
而isInterrupted()僅僅返回中斷標記。


標準的中斷寫法如下所示(中斷阻塞的執行緒和未阻塞的執行緒)

終止執行緒的方式
Thread中的stop()和suspend()方法,由於固有的不安全性,已經建議不再使用!
下面,我先分別討論執行緒在“阻塞狀態”和“執行狀態”的終止方式,然後再總結出一個通用的方式。

1 終止處於“阻塞狀態”的執行緒
通常,我們通過“中斷”方式終止處於“阻塞狀態”的執行緒。
當執行緒由於被呼叫了sleep(), wait(), join()等方法而進入阻塞狀態;若此時呼叫執行緒的interrupt()將執行緒的中斷標記設為true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException異常。將InterruptedException放在適當的為止就能終止執行緒,形式如下:

@Override
public void run() {
    try {
        while (true) {
            // 執行任務...
        }
    } catch (InterruptedException ie) {  
        // 由於產生InterruptedException異常,退出while(true)迴圈,執行緒終止!
    }
}

說明:在while(true)中不斷的執行任務,當執行緒處於阻塞狀態時,呼叫執行緒的interrupt()產生InterruptedException中斷。中斷的捕獲在while(true)之外,這樣就退出了while(true)迴圈!
注意:對InterruptedException的捕獲務一般放在while(true)迴圈體的外面,這樣,在產生異常時就退出了while(true)迴圈。否則,InterruptedException在while(true)迴圈體之內,就需要額外的新增退出處理。形式如下:

@Override
public void run() {
    while (true) {
        try {
            // 執行任務...
        } catch (InterruptedException ie) {  
            // InterruptedException在while(true)迴圈體內。
            // 當執行緒產生了InterruptedException異常時,while(true)仍能繼續執行!需要手動退出
            break;
        }
    }
}

說明:上面的InterruptedException異常的捕獲在whle(true)之內。當產生InterruptedException異常時,被catch處理之外,仍然在while(true)迴圈體內;要退出while(true)迴圈體,需要額外的執行退出while(true)的操作。

2 終止處於“執行狀態”的執行緒
通常,我們通過“標記”方式終止處於“執行狀態”的執行緒。其中,包括“中斷標記”和“額外新增標記”。
(01) 通過“中斷標記”終止執行緒。
形式如下:

@Override
public void run() {
    while (!isInterrupted()) {
        // 執行任務...
    }
}

說明:isInterrupted()是判斷執行緒的中斷標記是不是為true。當執行緒處於執行狀態,並且我們需要終止它時;可以呼叫執行緒的interrupt()方法,使用執行緒的中斷標記為true,即isInterrupted()會返回true。此時,就會退出while迴圈。
注意:interrupt()並不會終止處於“執行狀態”的執行緒!它會將執行緒的中斷標記設為true。

(02) 通過“額外新增標記”。
形式如下:

private volatile boolean flag= true;
protected void stopTask() {
    flag = false;
}

@Override
public void run() {
    while (flag) {
        // 執行任務...
    }
}

說明:執行緒中有一個flag標記,它的預設值是true;並且我們提供stopTask()來設定flag標記。當我們需要終止該執行緒時,呼叫該執行緒的stopTask()方法就可以讓執行緒退出while迴圈。
注意:將flag定義為volatile型別,是為了保證flag的可見性。即其它執行緒通過stopTask()修改了flag之後,本執行緒能看到修改後的flag的值。

綜合執行緒處於“阻塞狀態”和“執行狀態”的終止方式,比較通用的終止執行緒的形式如下:

@Override
public void run() {
    try {
        // 1. isInterrupted()保證,只要中斷標記為true就終止執行緒。
        while (!isInterrupted()) {
            // 執行任務...
        }
    } catch (InterruptedException ie) {  
        // 2. InterruptedException異常保證,當InterruptedException異常產生時,執行緒被終止。
    }
}