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);
}
}
運作幾次,結果略有不同
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等方法已經棄用,退出标記不夠靈活有時也有問題,是以目前最合适的解決方式是借助于中斷機制
中斷機制是一種處理邏輯,而不是說立即中斷
中斷機制是一種“請求---處理”模型,是一種軟中斷,并不會因為中斷的設定立即停止運作
中斷機制的邏輯借助于“中斷标志”,當請求一個線程中斷時,可以通過設定目标線程的中斷标志位進行操作
簡單的邏輯如下圖所示:
是以說,對于線程的停止的三種方式,中斷機制是一種更好的方式,而且也是一種更加友好的方式。
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();設定了标志位,但是線程仍舊繼續運作,完全并沒有停止的意思
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三個方法其實就是對于中斷标志位的操作
重新審視下方法,兩個執行個體方法一個靜态方法
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
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。
接下來看一個方法
測試線程是否被中斷。
中斷标志位将會根據參數ClearInterrupted的值決定是否會被清除
這是一個執行個體方法,是以需要依賴于某個執行個體對象
再仔細看看靜态方法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 方法對比、差別與聯系 多線程中篇(八)