【问题标题】:Thread.isInterrupted() returns false after thread has been terminated线程终止后,Thread.isInterrupted() 返回 false
【发布时间】:2014-01-07 10:39:45
【问题描述】:

考虑以下 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); 替换该行,测试仍然失败。这种行为是否记录在任何地方?

【问题讨论】:

  • 你有没有试过把sleep(1000)放在调用consumerThread.interrupt()?启动线程是本机调用,但我不确定在启动调用完成后线程实际上已经开始运行。
  • 是的,我猜错了,Alexei 下面的回答似乎可以解释症状。

标签: java concurrency


【解决方案1】:

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

【讨论】:

  • 目前看来,这种行为是实现细节,因为我在语言规范中没有发现这种特定情况。
【解决方案2】:

这已在 Java 14 中修复。

Thread.isInterrupted 如果线程被中断,则返回true,即使线程不活动。请参阅 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) 方法

【讨论】:

    【解决方案3】:

    来自 JavaDocs:“由于在中断时线程不活动而忽略的线程中断将通过此方法返回 false 来反映。”

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

    为并发系统进行单元测试非常棘手。您可以通过在测试中添加延迟来使其更加健壮,但不幸的是,这会减慢测试执行速度,因此您不能拥有很多。

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

    【讨论】:

    • 该解释与我在运行测试时得到的行为不符。您是对的,blockingThread 在被中断之前可能还没有达到 wait() 的调用,但即使达到了,当线程死亡时,中断状态显然会被清除,正如 Alexei 指出的那样。
    • 我已经用 sleep 测试了这种情况,结果总是一样的。所有线索都指向在线程终止时重置的标志。
    猜你喜欢
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2011-05-28
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2011-11-30
    相关资源
    最近更新 更多