2012-05-01 30 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),它会默默地吃掉你的线程中断状态。 '我的意思是,在每次可能的日志操作之前和之后,谁不检查线程中断状态?