我正在使用Executors.newCachedThreadPool()
和invokeAll
列表Callable
来执行长时间运行的多线程处理。
我的主线程被阻塞,直到所有线程完成,我可以处理invokeAll
返回的Futures。但是,如果其中一个invokeAll
抛出异常并终止其他线程,我希望Callable
立即返回。
使用execute
代替invokeAll
会阻止第一个future.get()
,而isDone()
不一定是引发执行的那个。{/ p>
使用忙碌等待循环查看所有期货并检查{{1}}似乎也不是最佳方式。
答案 0 :(得分:6)
您可以使用更复杂的同步机制,如锁存器,障碍或信号量,但请查看ExecutorCompletionService
。它是围绕ExecutorService
的轻量级包装器,允许您监听第一个完成的任务。这是一个简单的例子:
final ExecutorService executorService = Executors.newCachedThreadPool();
final ExecutorCompletionService<String> completionService =
new ExecutorCompletionService<String>(executorService);
for (int i = 0; i < 10; ++i) {
completionService.submit(new Task());
}
completionService.take().get();
代码非常简单。首先用executorService
包裹completionService
。之后你用它来一个接一个地提交任务。最后一行至关重要。它完成第一个任务并尝试检索结果。如果它抛出异常,它将在此重新抛出,包含ExecutionException
:
try {
completionService.take().get();
} catch (ExecutionException e) {
e.getCause(); //this was thrown from task!
}
在catch
块内,您可以以某种方式处理异常,例如取消剩余的任务或关闭整个线程池。
当然,您可以通过拨打take()
十次来等待所有任务完成。只要至少完成一项任务,每次调用都会阻止。