關於執行緒終止方法interrupt()
由於stop()方法已經過時和廢棄,是之前JDK設計有缺陷的方法,所以我們一般使用interrupt()方法來終止執行緒,但是interrupt()方法並不像stop()方法那樣暴力終止執行緒,通俗的說使用效果並沒有for+break語句那樣,馬上就終止迴圈。呼叫interrupt()方法僅僅是在當前執行緒中打了一個停止的標記,並不是真正意義上的停止執行緒。我們先來看一個簡單的示例:
public class InterruptDemo extends Thread {
@Override
public void run() {
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
}
public static void main(String[] args) {
try {
InterruptDemo interruptDemo = new InterruptDemo();
interruptDemo.start();
//讓執行緒休眠2秒
Thread.sleep(2000);
interruptDemo.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
複製程式碼
執行結果如下:
從執行結果來看,interrupt()方法並沒有終止執行緒,所以我們需要java提供的2個方法interrupted()和isInterrupted()來判斷它停止的標誌從而能正確的終止執行緒。但是這2個方法是很容易混淆的,下面我們通過原始碼解讀+測試小例子來把它們的區別和用法徹底搞清楚。Thread.interrupted()和this.isInterrupted()的區別
判斷執行緒是否是停止狀態,java中的JDK提供了兩種方法:
Thread.interrupted():測試當前執行緒是否已經中斷
this.isInterrupted():測試執行緒是否已經中斷
複製程式碼
這兩個方法有什麼差別呢?我們先看下JDK原始碼:
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
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);
複製程式碼
首先我們發現這個2個方法都呼叫了isInterrupted(boolean ClearInterrupted)這個方法,我們看這個方法的註解,它的意思是說如果一個執行緒已經被終止了,中斷狀態是否被重置取決於ClearInterrupted
的值,即ClearInterrupted為true時,中斷狀態會被重置,為false則不會被重置。
然後我們比較這2個方法的差別,結果就很明顯了,可以看出,interrupted()是靜態方法,所以我們用Thread.interrupted()方法表示,它呼叫的是currentThread().isInterrupted(true)方法,即說明是返回當前執行緒的是否已經中斷的狀態值,而且有清理中斷狀態的機制。而isInterrupted()是一個例項方法,所以我們用this.isInterrupted()方法表示,它呼叫的是isInterrupted(false)方法,意思是返回執行緒是否已經中斷的狀態值,與Thread.interrupted()方法相反,它沒有清理中斷狀態的機制。(PS:這裡看不懂沒關係,後面會用例子驗證)
1. Thread.interrupted()
下面我們先研究一下Thread.interrupted()方法,請看下面的一個例子:
public class InterruptDemo1 extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 50000; i++) {
System.out.println("i=" + (i + 1));
}
}
public static void main(String[] args) {
InterruptDemo1 thread=new InterruptDemo1();
thread.start();
try {
Thread.sleep(1000);
thread.interrupt();
System.out.println("是否已經停止 1?="+Thread.interrupted());
System.out.println("是否已經停止 2?="+Thread.interrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end!");
}
複製程式碼
執行結果如下:
從執行的結果來看,執行緒並未終止,這也就證明了interrupted()方法的解釋:測試當前執行緒是否已經中斷,這個“當前執行緒”是main,它從未中斷過,所以2個結果都是false。 哪如何讓main執行緒終止呢?
public class InterruptDemo2 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("是否停止 1?="+Thread.interrupted());
System.out.println("是否停止 2?="+Thread.interrupted());
System.out.println("end!");
}
}
複製程式碼
執行結果如下:
是否停止 1?=true
是否停止 2?=false
end!
複製程式碼
從執行結果來看,方法interrupted()的確能判斷出當前執行緒是否是中斷(停止)狀態。第二個false是什麼意思呢,這就驗證了我們上面所說的中斷狀態清除的情況,就是說interrupted()會清除中斷狀態,如果連續2次呼叫該方法,則第二次會返回false值(在第一次呼叫已清除了中端狀態之後,且第二次呼叫檢驗完中斷狀態之前,當前執行緒再次中斷的情況除外)。
2. this.isInterrupted()
分析完Thread.interrupted()方法之後,我們下面再來分析this.isInterrupted()方法:
public class InterruptDemo3 extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 50000; i++) {
System.out.println("i=" + (i + 1));
}
}
public static void main(String[] args) {
InterruptDemo3 thread = new InterruptDemo3();
thread.start();
try {
Thread.sleep(1000);
thread.interrupt();
System.out.println("是否已經停止 1?=" + thread.isInterrupted());
System.out.println("是否已經停止 2?=" + thread.isInterrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end!");
}
}
複製程式碼
執行結果:
從結果看,2個值都為true,說明方法isInterrupted()並沒有清除中斷狀態標誌,和我們之前分析原始碼的結果一致。
總結
- interrupted()是static方法,呼叫的時候要用Thread.interrupted(),而isInterrupted()是例項方法,呼叫時要用執行緒的例項呼叫;
- Thread.interrupted():測試當前執行緒是否已經是中斷狀態,執行後具有將狀態標誌清除為false的功能;
- this.isInterrupted():測試執行緒Thread物件是否已經是中斷狀態,但不清除狀態標誌。
參考
《java多執行緒程式設計核心技術》