在下面這個程序中,一個線程試圖中斷自己,然后檢查中斷是否成功。它會打印什么呢?
public class SelfInterruption {
public static void main(String[ ] args) {
Thread.currentThread().interrupt();
if(Thread.interrupted()) {
System.out.println("Interrupted: " +
Thread.interrupted());
} else{
System.out.println("Not interrupted: " +
Thread.interrupted());
}
}
}
雖然一個線程中斷自己不是很常見,但這也不是沒有聽說過的。當一個方法捕捉到了一個InterruptedException異常,而且沒有做好處理這個異常的準備時,那么這個方法通常會將該異常重新拋出(rethrow)。但是由于這是一個“被檢查的異?!?,所以只有在方法聲明允許的情況下該方法才能夠?qū)惓V匦聮伋觥H绻荒苤匦聮伋?,該方法可以通過中斷當前線程對異常“再構(gòu)建”(reraise)。這種方式工作得很好,所以這個程序中的線程中斷自己應該是沒有任何問題的。所以,該程序應該進入if語句的第一個分支,打印出 Interrupted: true。如果你運行該程序,你會發(fā)現(xiàn)并不是這樣。但是它也沒有打印 Not interrupted: false,它打印的是 Interrupted: false。
看起來該程序好像不能確定線程是否被中斷了。當然,這種看法是毫無意義的。實際上發(fā)生的事情是,Thread.interrupted方法第一次被調(diào)用的時候返回了true,并且清除了線程的中斷狀態(tài),所以在if-then-else語句的分支中第2次調(diào)用該方法的時候,返回的就是false。調(diào)用Thread.interrupted方法總是會清除當前線程的中斷狀態(tài)。方法的名稱沒有為這種行為提供任何線索,而對于5.0版本,在相應的文檔中有一句話概要地也同樣具有誤導性地敘述道:“測試當前的線程是否中斷”[Java-API]。所以,可以理解為什么很多程序員都沒有意識到Thread.interrupted方法會對線程的中斷狀態(tài)造成影響。
Thread類有2個方法可以查詢一個線程的中斷狀態(tài)。另外一個方法是一個名為isInterrupted的實例方法,而它不會清除線程的中斷狀態(tài)。如果使用這個方法重寫程序,它就會打印出我們想要的結(jié)果true:
public class SelfInterruption {
public static void main(String[ ] args) {
Thread.currentThread().interrupt();
if(Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted: " +
Thread.currentThread().isInterrupted());
}else{
System.out.println("Not interrupted: " +
Thread.currentThread().isInterrupted());
}
}
}
這個謎題的教訓是:不要使用Thread.interrupted方法,除非你想要清除當前線程的中斷狀態(tài)。如果你只是想查詢中斷狀態(tài),請使用isInterrupted方法。這里給API設(shè)計者們的教訓是方法的名稱應該用來描述它們主要功能。根據(jù)Thread.interrupted方法的行為,它的名稱應該是 clearInterruptStatus,因為相對于它對中斷狀態(tài)的改變,它的返回值是次要的。特別是當一個方法的名稱并不完美的時候,文檔是否能清楚地描述它的行為就顯得非常重要了。
public class SelfInterruption {
public static void main(String[ ] args) {
Thread.currentThread().interrupt();
if(Thread.interrupted()) {
System.out.println("Interrupted: " +
Thread.interrupted());
} else{
System.out.println("Not interrupted: " +
Thread.interrupted());
}
}
}
雖然一個線程中斷自己不是很常見,但這也不是沒有聽說過的。當一個方法捕捉到了一個InterruptedException異常,而且沒有做好處理這個異常的準備時,那么這個方法通常會將該異常重新拋出(rethrow)。但是由于這是一個“被檢查的異?!?,所以只有在方法聲明允許的情況下該方法才能夠?qū)惓V匦聮伋觥H绻荒苤匦聮伋?,該方法可以通過中斷當前線程對異常“再構(gòu)建”(reraise)。這種方式工作得很好,所以這個程序中的線程中斷自己應該是沒有任何問題的。所以,該程序應該進入if語句的第一個分支,打印出 Interrupted: true。如果你運行該程序,你會發(fā)現(xiàn)并不是這樣。但是它也沒有打印 Not interrupted: false,它打印的是 Interrupted: false。
看起來該程序好像不能確定線程是否被中斷了。當然,這種看法是毫無意義的。實際上發(fā)生的事情是,Thread.interrupted方法第一次被調(diào)用的時候返回了true,并且清除了線程的中斷狀態(tài),所以在if-then-else語句的分支中第2次調(diào)用該方法的時候,返回的就是false。調(diào)用Thread.interrupted方法總是會清除當前線程的中斷狀態(tài)。方法的名稱沒有為這種行為提供任何線索,而對于5.0版本,在相應的文檔中有一句話概要地也同樣具有誤導性地敘述道:“測試當前的線程是否中斷”[Java-API]。所以,可以理解為什么很多程序員都沒有意識到Thread.interrupted方法會對線程的中斷狀態(tài)造成影響。
Thread類有2個方法可以查詢一個線程的中斷狀態(tài)。另外一個方法是一個名為isInterrupted的實例方法,而它不會清除線程的中斷狀態(tài)。如果使用這個方法重寫程序,它就會打印出我們想要的結(jié)果true:
public class SelfInterruption {
public static void main(String[ ] args) {
Thread.currentThread().interrupt();
if(Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted: " +
Thread.currentThread().isInterrupted());
}else{
System.out.println("Not interrupted: " +
Thread.currentThread().isInterrupted());
}
}
}
這個謎題的教訓是:不要使用Thread.interrupted方法,除非你想要清除當前線程的中斷狀態(tài)。如果你只是想查詢中斷狀態(tài),請使用isInterrupted方法。這里給API設(shè)計者們的教訓是方法的名稱應該用來描述它們主要功能。根據(jù)Thread.interrupted方法的行為,它的名稱應該是 clearInterruptStatus,因為相對于它對中斷狀態(tài)的改變,它的返回值是次要的。特別是當一個方法的名稱并不完美的時候,文檔是否能清楚地描述它的行為就顯得非常重要了。

