我最近继承了一个几乎没有Thread安全性的大型Java应用程序。我目前正在处理的是让所有线程正确处理被中断而不是使用非常糟糕的Thread.stop()
。
问题的部分原因是我不知道每个方法都会调用清除中断标志。
目前我知道以下内容将清除中断标志:
Thread.interrupted()
Thread.sleep(long)
Thread.join()
Thread.join(long)
Object.wait()
Object.wait(long)
我还缺少什么?谢谢
答案 0 :(得分:36)
问题的部分原因是我不知道每个方法都会调用清除中断标志。
重要的是要澄清以下方法通过调用它们来清除中断标志:
Thread.interrupted()
Thread.isInterrupted(true) -- added to your list
因此,应始终使用Thread.currentThread().isInterrupted()
代替。
以下方法将通过立即抛出InterruptedException
来清除中断标志,如果它们被调用,则线程被中断或如果线程< em>已经中断,然后调用它们(参见下面的junit代码)。所以它不是清除标志的方法,抛出异常就是这样。
Thread.sleep(long)
Thread.sleep(long, int) – added to your list
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
Process.waitFor() – added to your list
ExecutorService.invokeAll(...) – added to your list
ExecutorService.invokeAny(...) – added to your list
ExecutorService.awaitTermination(...) – added to your list
CompletionService.poll(...) – added to your list
CompletionService.take(...) – added to your list
CountDownLatch.await(...) – added to your list
CyclicBarrier.await(...) – added to your list
Semaphore.acquire(...) – added to your list
Semaphore.tryAcquire(...) – added to your list
Lock.lockInteruptibly() – added to your list
Lock.tryLock(...) – 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());
答案 1 :(得分:14)
常见约定如下:任何抛出InterruptedException
(+ Thread.interrupted()
)的方法都会清除中断标志。
因此,为了使您的线程可以中断,您需要找到InterruptedException
被捕获的所有位置,而无需重新启动它或恢复中断标志。由于InterruptedException
是一个经过检查的例外,因此不难做到。
答案 2 :(得分:1)
这是一个超级有趣的例子:
版本1.1.4之前的ch.qos.logback.core.AsyncAppenderBase捕获并吞下InterruptedException而不重置线程上的标志。所以,如果你使用任何路由到这个记录器的东西(比如slf4j),它会默默地吃你的线程中断状态。 &#39; Cos,我的意思是,谁不会在每次可能的日志操作之前和之后检查线程中断状态?