天天看點

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

interrupt interrupted isInterrupted 是三個“長相”非常類似的方法。

本文将對這三個方法簡單的對比下,首先了解下線程停止的方式

線程停止方式

在Java中如果想停止一個線程,有三種方法

  • 采用退出标志,使得run方法執行完之後線程自然終止
  • 使用stop強行終止線程,但該方法由于安全問題已經被deprecated
  • 使用中斷機制

退出标志

public class T9 extends Thread {
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running){
System.out.println("i am working ....");
}
}
public static void main(String[] args) {
T9 myThread = new T9();
myThread.setRunning(true);
myThread.start();
try {
TimeUnit.MILLISECONDS.sleep(2);
} catch (Exception e) {
}
myThread.setRunning(false);
}
}      

運作幾次,結果略有不同

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

stop 棄用

public class T9 extends Thread {
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
System.out.println("i am working ....");
}
}
public static void main(String[] args) {
T9 myThread = new T9();
myThread.setRunning(true);
myThread.start();
try {
TimeUnit.MILLISECONDS.sleep(2);
} catch (Exception e) {
}
myThread.stop();
}
}      

中斷機制

stop等方法已經棄用,退出标記不夠靈活有時也有問題,是以目前最合适的解決方式是借助于中斷機制

中斷機制是一種處理邏輯,而不是說立即中斷

中斷機制是一種“請求---處理”模型,是一種軟中斷,并不會因為中斷的設定立即停止運作

中斷機制的邏輯借助于“中斷标志”,當請求一個線程中斷時,可以通過設定目标線程的中斷标志位進行操作

簡單的邏輯如下圖所示:

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

是以說,對于線程的停止的三種方式,中斷機制是一種更好的方式,而且也是一種更加友好的方式。

public class T9 extends Thread {
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
System.out.println("i am working ....");
}
}
public static void main(String[] args) {
T9 myThread = new T9();
myThread.setRunning(true);
myThread.start();
myThread.interrupt();
}
}      

上面的代碼中,盡管我們通過myThread.interrupt();設定了标志位,但是線程仍舊繼續運作,完全并沒有停止的意思

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)
public class T9 extends Thread {
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
if (Thread.currentThread().isInterrupted()) {
break;
}
System.out.println("i am working ....");
}
}
public static void main(String[] args) {
T9 myThread = new T9();
myThread.setRunning(true);
myThread.start();
try {
TimeUnit.MILLISECONDS.sleep(2);
} catch (Exception e) {
}
myThread.interrupt();
}
}      

上面代碼中,在run方法中判斷中斷标志位,如果發現中斷标志被置位,那麼break,也就是跳出循環

主函數中,線程啟動後,主線程休眠2毫秒然後将myThread中斷,程式運作一段時間後終止運作

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

是以可以看得出來,借助于中斷機制對一個線程進行處理,進行中斷标志置位,并不會對線程的運作産生影響,到底有何影響,重點要看到底你面對中斷标志位會做什麼處理。

中斷标志位

通過上面的分析,我們可以很清楚的看得出來,中斷機制的核心就是借助于中斷标志位

而 interrupt interrupted isInterrupted三個方法其實就是對于中斷标志位的操作

重新審視下方法,兩個執行個體方法一個靜态方法

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

API文檔

public void interrupt()

中斷一個線程(設定标志位)

除非是目前線程正在中斷自己(這在任何情況下都是允許的),否則該線程的 checkAccess 方法就會被調用,這可能抛出 SecurityException。

如果線程在調用 Object 類的 wait()、wait(long) 或 wait(long, int) 方法,或者該類的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法過程中受阻,則其中斷狀态将被清除,它還将收到一個 InterruptedException。

如果該線程在可中斷的通道上的 I/O 操作中受阻,則該通道将被關閉,該線程的中斷狀态将被設定并且該線程将收到一個 ClosedByInterruptException。

如果該線程在一個 Selector 中受阻,則該線程的中斷狀态将被設定,它将立即從選擇操作傳回,并可能帶有一個非零值,就好像調用了選擇器的 wakeup 方法一樣。

如果以前的條件都沒有儲存,則該線程的中斷狀态将被設定。

中斷一個不處于活動狀态的線程不需要任何作用。

抛出:

SecurityException - 如果目前線程無法修改該線程

注意:

如果不是線程自己在中斷自己的話,會有安全管理器先進行校驗,如果權限不夠,将會抛出SecurityException

如果位于特殊的等待狀态,比如調用wait()、wait(long)或者join()或者sleep()等方法,中斷标志位将會被清除,并且收到一個InterruptedException

前面說到中斷标志被置位不影響線程的正常運作,但是這個InterruptedException又是什麼意思?

中斷标志的确是不影響線程的運作,要看線程對于中斷标志是如何進行處理的

但是如果處于等待的話,就會抛出異常

簡單說,當一個線程正常運作的時候,可以不用搭理中斷标志位;

但是如果比如在等人,在睡覺,一旦被中斷就會被吵醒,吵醒了、不爽了、自然要發發牢騷,這個牢騷就是InterruptedException

public boolean isInterrupted()

測試線程是否已經中斷

線程的中斷狀态不受該方法的影響

A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false.

在中斷發生時,如果一個線程并不是alive的,中斷操作将會被忽略,也會通過這個方法傳回false反映出來

傳回:

如果該線程已經中斷,則傳回 true;否則傳回 false。

如果一個線程根本都不是alive的,調用這個方法也是傳回false

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

public static boolean interrupted()

測試目前線程是否已經中斷。

線程的中斷狀态 由該方法清除。

換句話說,如果連續兩次調用該方法,則第二次調用将傳回 false(在第一次調用已清除了其中斷狀态之後,且第二次調用檢驗完中斷狀态前,目前線程再次中斷的情況除外)。

在中斷發生時,如果一個線程并不是alive的,中斷操作将會被忽略,也會通過這個方法傳回false反映出來

A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false.

傳回:

如果目前線程已經中斷,則傳回 true;否則傳回 false。

接下來看一個方法

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

測試線程是否被中斷。

中斷标志位将會根據參數ClearInterrupted的值決定是否會被清除

這是一個執行個體方法,是以需要依賴于某個執行個體對象

再仔細看看靜态方法interrupted

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

内部借助于上面的那個私有方法

他的含義就是,測試目前線程是否被中斷,并且清除中斷标志位

而對于執行個體方法isInterrupted,仍舊是借助于本地方法,測試某個線程是否被中斷,但是并不會清除線程的中斷标志

interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)

小結

三個方法全都是用來對線程中斷标志進行操作的

public void interrupt()、public boolean isInterrupted()作為執行個體方法,是對指定線程的操作

假設中斷标志位interruptState

那麼對于interrupt來說相當于set方法

public void setInterruptState(boolean interruptState) {
    this.interruptState = interruptState;
  }      

對于isInterrupted來說,相當于get方法

public boolean isInterruptState() {
    return interruptState;
  }      

而對于interrupted() 則是相當于getter  and  setter,并且,是針對于目前線程的

總結

對于三個方法interrupt interrupted isInterrupted,重點是要了解中斷标志位

從getter和setter方法的角度了解的話,能夠更好地了解,從方法名中也可以很好地看得出來 

interrupt作為動詞,是以是使之中斷,自然是setter方法

而對于isInterrupted 典型的疑問句式,是以是對中斷标志位的測試 是getter方法

interrupted看起來就奇葩了一點,是以他是set和get ,并且是針對目前線程的

這樣的話就不會混淆了,畢竟名字的确是有些接近

原文位址:interrupt interrupted isInterrupted 方法對比、差別與聯系 多線程中篇(八)