2

我正在尝试编写一个集成测试,导致InterruptedException从生产代码中引发一个:

@Test
public void test() {
    productionObject = new ProductionObject(
            com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor());
    Thread.currentThread().interrupt();
    assertThat(productionObject.execute(), equalTo(defaultResponse));
}

InsideproductionObject的实现:

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 来模拟更高的负载;-) 任何人都可以发现我的错误,给我一些关于在哪里看的建议,或建议可以帮助我的工具?

4

3 回答 3

1

奇怪的。我以与您相同的方式阅读代码。我懂了:

  1. FutureTask.get()来电Sync.get()。我假设我们正在处理FutureTask这里。
  2. Sync.get()来电Sync.innerGet()
  3. Sync.innerGet()来电acquireSharedInterruptibly(0)
  4. 其中有代码:

    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());
}
于 2013-02-21T16:11:23.603 回答
0

在这种情况下使用sameThreadExecutor()实际上可能会适得其反,因为中断可能会发生在其中一项任务中。否则代码看起来很好。尝试使用启动实际的其他线程并让其中一个任务等待足够长的时间等待您的中断。

于 2013-02-21T16:15:30.900 回答
0

我通过从内部Callable而不是从测试方法本身中断线程来“修复”这个问题。这使得中断更接近于调用acquireSharedInterruptibly()

我只能想象代码路径上的某个地方有时会清除中断标志(可能是由 JUnit 或 Maven surefire,它们并行执行测试方法)。我可能只是减少了竞争条件的可能性,而不是修复它:-/

于 2013-02-22T10:38:44.207 回答