【问题标题】:Methods that Clear the Thread.interrupt() flag清除 Thread.interrupt() 标志的方法
【发布时间】:2012-05-01 17:53:59
【问题描述】:

我最近继承了一个几乎没有线程安全的大型 Java 应用程序。我目前正在做的是让所有线程正确处理被中断而不是使用非常糟糕的Thread.stop()

部分问题是我不知道清除中断标志的每个方法调用。

目前我知道以下会清除中断标志:

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

我还缺少什么?谢谢

【问题讨论】:

    标签: java multithreading interrupt


    【解决方案1】:

    部分问题是我不知道清除中断标志的每个方法调用。

    需要澄清的是,以下方法只需调用它们即可清除中断标志:

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

    因此,应始终使用Thread.currentThread().isInterrupted()

    以下方法将通过立即清除中断标志,如果它们被调用然后线程被中断如果线程被抛出InterruptedException已经中断,然后他们被调用(见下面的junit代码)。所以不是清除标志的方法,而是抛出异常。

    您的初始清单:

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

    已添加到您的列表中:

    Thread.sleep(long, int)
    Thread.join(int, long)
    Thread.isInterrupted(true)
    Object.wait(int, long)
    BlockingQueue.put(...)
    BlockingQueue.offer(...)
    BlockingQueue.take(...)
    BlockingQueue.poll(...)
    Future.get(...)
    Process.waitFor()
    ExecutorService.invokeAll(...)
    ExecutorService.invokeAny(...)
    ExecutorService.awaitTermination(...)
    CompletionService.poll(...)
    CompletionService.take(...)
    CountDownLatch.await(...)
    CyclicBarrier.await(...)
    Semaphore.acquire(...)
    Semaphore.tryAcquire(...)
    Lock.lockInteruptibly()
    Lock.tryLock(...)
    

    请注意,捕获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());
    

    【讨论】:

      【解决方案2】:

      常见约定如下:任何抛出 InterruptedException (+ Thread.interrupted()) 的方法都会清除中断标志。

      因此,为了使您的线程可中断,您需要找到InterruptedException 被捕获的所有位置,而无需追溯或恢复中断标志。由于InterruptedException 是一个已检查异常,所以并​​不难做到。

      【讨论】:

      • 这是我执行的代码库的第一次传递,但是我面临的情况是以前的程序员会捕获一般异常而不是 InterruptedException。
      【解决方案3】:

      这是一个超级有趣的例子:

      ch.qos.logback.core.AsyncAppenderBase 1.1.4 之前的版本捕获并吞下 InterruptedException 而不重置线程上的标志。

      所以,如果你使用任何路由到这个记录器的东西(比如 slf4j),它会默默地吃掉你的线程中断状态。 '因为,我的意思是,谁不检查每个可能的日志操作前后的线程中断状态?

      【讨论】:

        猜你喜欢
        • 2018-10-07
        • 1970-01-01
        • 2013-04-02
        • 1970-01-01
        • 2018-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        相关资源
        最近更新 更多