清除Thread.interrupt()标志的方法
我最近inheritance了一个几乎没有Thread安全性的大型Java应用程序。 我目前正在研究的是让所有线程正确处理被中断而不是使用非常糟糕的Thread.stop()
。
问题的一部分是我不知道每个方法调用清除中断标志。
目前我知道以下将清除中断标志:
Thread.interrupted() Thread.sleep(long) Thread.join() Thread.join(long) Object.wait() Object.wait(long)
我还缺少什么? 谢谢
问题的一部分是我不知道每个方法调用清除中断标志。
重要的是要澄清以下方法通过调用它们来清除中断标志:
Thread.interrupted() Thread.isInterrupted(true) -- added to your list
因此,应始终使用Thread.currentThread().isInterrupted()
。
以下方法将通过立即抛出InterruptedException
来清除中断标志,如果它们被调用然后线程被中断或线程已被中断然后被调用(参见下面的junit代码)。 所以它不是清除标志的方法,抛出exception就是这样。
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());
常见的约定如下:任何抛出InterruptedException
(+ Thread.interrupted()
)的方法都会清除中断标志。
因此,为了使您的线程可以中断,您需要找到InterruptedException
被捕获的所有位置,而无需重新启动它或恢复中断标志。 由于InterruptedException
是一个经过检查的exception,因此并不难。
这是一个超级有趣的例子:
版本1.1.4之前的ch.qos.logback.core.AsyncAppenderBase捕获并吞下InterruptedException而不重置线程上的标志。
所以,如果你使用任何路由到这个记录器的东西(比如slf4j),它会默默地吃你的线程中断状态。 ‘是的,我的意思是,谁不检查每个可能的日志操作之前和之后的线程中断状态?