2012-05-01 32 views
16

我最近繼承了一個幾乎沒有線程安全性的大型Java應用程序。我目前的工作是讓所有線程正確處理被中斷,而不是使用非常糟糕的Thread.stop()清除Thread.interrupt()標誌的方法

問題的一部分是我不知道每個方法調用那裏清除中斷標誌。

目前我知道下面將清除中斷標誌:

Thread.interrupted() 
Thread.sleep(long) 
Thread.join() 
Thread.join(long) 
Object.wait() 
Object.wait(long) 

還有什麼我缺少什麼?謝謝

回答

25

問題的一部分是,我不知道每個方法調用那裏清除中斷標誌。

必須明確指出,通過下列方法只是稱他們清除中斷標誌是很重要的:

Thread.interrupted() 
Thread.isInterrupted(true) -- added to your list 

爲此Thread.currentThread().isInterrupted()應該總是代替。

下面的方法將立即InterruptedException清除中斷標誌或者如果他們被稱爲然後線程被中斷如果線程已經打斷了,然後他們被稱爲(見下面的JUnit代碼)。所以它不是清除標誌的方法,拋出異常。

Thread.sleep(long) 
Thread.join() 
Thread.join(long) 
Thread.join(int, long) – added to your list 
Object.wait() 
Object.wait(long) 
Object.wait(int, long) – added to your list 
BlockingQueue.put(...) – added to your list 
BlockingQueue.offer(...) – added to your list 
BlockingQueue.take(...) – added to your list 
BlockingQueue.poll(...) – added to your list 
Future.get(...) – added to your list 

請注意任何代碼映入InterruptedException是立即重新中斷線程的正確模式。我們這樣做的情況下,其他人都是靠thread.isInterrupted()方法:

try { 
    ... 
} catch (InterruptedException e) { 
    // immediately re-interrupt the thread 
    Thread.currentThread().interrupt(); 
    // log the exception or [likely] quit the thread 
} 

JUnit的代碼,演示了一些這樣的:

assertFalse(Thread.currentThread().isInterrupted()); 
// you can do this from another thread by saying: someThread.interrupt(); 
Thread.currentThread().interrupt(); 
// this method does _not_ clear the interrupt flag 
assertTrue(Thread.currentThread().isInterrupted()); 
// but this one _does_ and should probably not be used 
assertTrue(Thread.interrupted()); 
assertFalse(Thread.currentThread().isInterrupted()); 
Thread.currentThread().interrupt(); 
assertTrue(Thread.currentThread().isInterrupted()); 
try { 
    // this throws immediately because the thread is _already_ interrupted 
    Thread.sleep(1); 
    fail("will never get here"); 
} catch (InterruptedException e) { 
    // and when the InterruptedException is throw, it clears the interrupt 
    assertFalse(Thread.currentThread().isInterrupted()); 
    // we should re-interrupt the thread so other code can use interrupt status 
    Thread.currentThread().interrupt(); 
} 
assertTrue(Thread.currentThread().isInterrupted()); 
10

常見約定如下:任何引發InterruptedException(+ Thread.interrupted())的方法都會清除中斷標誌。

因此,爲了讓你的線程中斷,你需要找到InterruptedException被捕獲的所有地方,而不用重新調用它或恢復中斷標誌。由於InterruptedException是一個檢查異常,所以不難做到。

+0

這是第一次拋出我執行的代碼庫,但是我面臨的情況是以前的程序員會捕獲一般異常而不是InterruptedException。 – OverflowingStack

1

這裏是一個超級好玩的例子:

ch.qos.logback 。1.1.4版之前的.core.AsyncAppenderBase會捕獲併吞下InterruptedException,而不會重置線程上的標誌。

所以,如果你使用任何路由到這個記錄器(如slf4j),它會默默地吃掉你的線程中斷狀態。 '我的意思是,在每次可能的日誌操作之前和之後,誰不檢查線程中斷狀態?