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);
}
}
運行幾次,結果略有不同
image_5c64c4ae_2bf0

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等方法已經棄用,退出標記不夠靈活有時也有問題,所以目前最合適的解決方式是借助於中斷機制
中斷機制是一種處理邏輯,而不是說立即中斷
中斷機制是一種“請求---處理”模型,是一種軟中斷,並不會因為中斷的設置立即停止運行
中斷機制的邏輯借助於“中斷標志”,當請求一個線程中斷時,可以通過設置目標線程的中斷標志位進行操作
簡單的邏輯如下圖所示:
image_5c64c4ae_523
所以說,對於線程的停止的三種方式,中斷機制是一種更好的方式,而且也是一種更加友好的方式。
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();設置了標志位,但是線程仍舊繼續運行,完全並沒有停止的意思
image_5c64c4ae_46e8
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中斷,程序運行一段時間后終止運行
image_5c64c4ae_3b32
所以可以看得出來,借助於中斷機制對一個線程進行處理,進行中斷標志置位,並不會對線程的運行產生影響,到底有何影響,重點要看到底你面對中斷標志位會做什么處理。

中斷標志位

通過上面的分析,我們可以很清楚的看得出來,中斷機制的核心就是借助於中斷標志位
而 interrupt interrupted isInterrupted三個方法其實就是對於中斷標志位的操作
重新審視下方法,兩個實例方法一個靜態方法
image_5c64c4ae_c76
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
image_5c64c4ae_3d75
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。
接下來看一個方法
image_5c64c4ae_6e8a
測試線程是否被中斷。
中斷標志位將會根據參數ClearInterrupted的值決定是否會被清除
這是一個實例方法,所以需要依賴於某個實例對象
再仔細看看靜態方法interrupted
image_5c64c4ae_37c4
內部借助於上面的那個私有方法
他的含義就是,測試當前線程是否被中斷,並且清除中斷標志位
而對於實例方法isInterrupted,仍舊是借助於本地方法,測試某個線程是否被中斷,但是並不會清除線程的中斷標志
image_5c64c4ae_c9c

小結

三個方法全都是用來對線程中斷標志進行操作的
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 ,並且是針對當前線程的
這樣的話就不會混淆了,畢竟名字的確是有些接近


免責聲明!

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



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