Thread.isInterrupted()在线程终止后返回false

时间:2014-01-07 10:39:45

标签: java concurrency

考虑以下JUnit测试:

@Test
public void testSettingInterruptFlag() throws InterruptedException {

    Thread blockingThread = new Thread(new Runnable() {
        @Override
        public synchronized void run() {

            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    });
    blockingThread.start();
    blockingThread.interrupt();
    blockingThread.join();
    assertTrue(blockingThread.isInterrupted());
}

即使设置了中断状态,测试也会失败。 我怀疑行blockingThread.join();重置了标志,但即使用Thread.sleep(3000);替换该行,测试仍然失败。这种行为是否记录在任何地方?

3 个答案:

答案 0 :(得分:4)

我们看到的是,当该线程完成时,线程的中断状态被清除。它没有在http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html中记录,因此可以被视为规范或实现错误。

答案 1 :(得分:3)

此问题已在 OpenJDK 14中修复。请参见Oracle的release notesJDK-8229516

java.lang.Thread::interrupt的规范仅允许实现跟踪活动线程的中断状态,并且以前就是这种情况。 从此版本开始,Thread的中断状态总是可用的。 ,并且如果您在启动线程t之前中断了该线程,或者终止后,查询t.isInterrupted()将返回true。

以下段落已添加到Thread#interrupt的javadoc中:

在JDK参考实现中,未激活的线程的中断仍会记录该中断请求,并将通过interruptedisInterrupted()进行报告。

因此问题中的测试成功运行于:

openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment (build 14.0.2+12)
OpenJDK 64-Bit Server VM (build 14.0.2+12, mixed mode)

中断标志存储为Thread类中的字段:

/* Interrupt state of the thread - read/written directly by JVM */
private volatile boolean interrupted;

isInterrupted方法仅返回标志:

public boolean isInterrupted() {
    return interrupted;
}

以前,它委托给native isInterrupted(boolean)方法

答案 2 :(得分:0)

从JavaDocs:“线程中断被忽略,因为在中断时线程不活动将被此方法反映返回false。”

当您调用“Thread.interrupt()”时,您的线程尚未启动。

对并发系统进行单元测试非常棘手。您可以通过在测试中添加延迟来使其更加健壮,但不幸的是,这会降低测试执行速度,因此您无法使用它们。

要使其安全失败,您需要在线程类中添加一个布尔标志,告诉测试它已经启动并等待在忙循环中引发该标志。只有这样你才能调用中断和加入。