考虑以下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);
替换该行,测试仍然失败。这种行为是否记录在任何地方?
答案 0 :(得分:4)
我们看到的是,当该线程完成时,线程的中断状态被清除。它没有在http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html中记录,因此可以被视为规范或实现错误。
答案 1 :(得分:3)
此问题已在 OpenJDK 14中修复。请参见Oracle的release notes和JDK-8229516。
java.lang.Thread::interrupt
的规范仅允许实现跟踪活动线程的中断状态,并且以前就是这种情况。 从此版本开始,Thread
的中断状态总是可用的。 ,并且如果您在启动线程t
之前中断了该线程,或者终止后,查询t.isInterrupted()
将返回true。
以下段落已添加到Thread#interrupt
的javadoc中:
在JDK参考实现中,未激活的线程的中断仍会记录该中断请求,并将通过
interrupted
和isInterrupted()
进行报告。
因此问题中的测试成功运行于:
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()”时,您的线程尚未启动。
对并发系统进行单元测试非常棘手。您可以通过在测试中添加延迟来使其更加健壮,但不幸的是,这会降低测试执行速度,因此您无法使用它们。
要使其安全失败,您需要在线程类中添加一个布尔标志,告诉测试它已经启动并等待在忙循环中引发该标志。只有这样你才能调用中断和加入。