在调用Future.get()之前中断线程

时间:2013-02-21 16:07:12

标签: java multithreading interrupt future

我正在尝试编写一个集成测试,导致从生产代码中引发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来模拟更高的负载;-)任何人都可以发现我的错误,给我一些关于在哪里看的建议,或建议可以帮助我的工具?

3 个答案:

答案 0 :(得分:1)

奇怪。我以与你相同的方式阅读代码。我明白了:

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

    if (Thread.interrupted())
        throw new InterruptedException();
    
  5. 我认为这总会抛出。也许存在某种竞争条件,所以线程还不知道它已被中断?你打断线程后有没有试过睡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,它们并行执行测试方法)。我可能只是减少了竞争条件的可能性,而不是修复它: - /