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