我正在尝试编写一个集成测试,导致从生产代码中引发InterruptedException
:
@Test
public void test() {
productionObject = new ProductionObject(
com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor());
Thread.currentThread().interrupt();
assertThat(productionObject.execute(), equalTo(defaultResponse));
}
内部productionObject
的实施:
try {
for (Future<T> future : executorService.invokeAll(tasks))) {
results.add(future.get());
}
return results;
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // preserve interrupt flag
return defaultResponse;
}
在AbstractQueuedSynchronizer.acquireSharedInterruptibly()
内,我看到了:
if (Thread.interrupted())
throw new InterruptedException();
所以我希望这个测试能够一致地通过。
我在构建服务器中看到此失败(results
被返回而不是defaultResponse
)。我一直无法在本地重现失败,在一段时间(真实)循环中运行测试,并通过软件渲染运行glxgears来模拟更高的负载;-)任何人都可以发现我的错误,给我一些关于在哪里看的建议,或建议可以帮助我的工具?
答案 0 :(得分:1)
奇怪。我以与你相同的方式阅读代码。我明白了:
FutureTask.get()
来电Sync.get()
。我假设我们在这里处理FutureTask
。Sync.get()
来电Sync.innerGet()
Sync.innerGet()
来电acquireSharedInterruptibly(0)
; 关闭代码:
if (Thread.interrupted())
throw new InterruptedException();
我认为这总会抛出。也许存在某种竞争条件,所以线程还不知道它已被中断?你打断线程后有没有试过睡100码?
我刚刚在我的多CPU Mac上运行了以下测试,它永远不会失败,所以它看起来不像竞争条件 - 至少我的架构和JRE版本1.6.0_41。
for (long i = 0; i < 10000000; i++) {
Thread.currentThread().interrupt();
assertTrue(Thread.interrupted());
}
答案 1 :(得分:0)
在此上下文中使用sameThreadExecutor()
实际上可能会产生反作用,因为中断可能不会发生在其中一个任务中。否则代码看起来很好。尝试使用踢开实际的其他线程,并让其中一个任务等待足够长的时间来中断。
答案 2 :(得分:0)
我通过在Callable
内而不是从测试方法本身中断线程来“修复”这个问题。这使得中断更接近于调用acquireSharedInterruptibly()
。
我只能想象在代码路径上的某个地方,中断标志有时会被清除(可能是由JUnit或Maven surefire,它们并行执行测试方法)。我可能只是减少了竞争条件的可能性,而不是修复它: - /