【问题标题】:Return to main thread as soon as one child thread throws an exception一有子线程抛出异常就返回主线程
【发布时间】:2012-12-25 06:14:41
【问题描述】:

我正在使用Executors.newCachedThreadPool()invokeAllCallables 列表来执行长时间运行的多线程处理。 我的主线程被阻塞,直到所有线程都完成并且我可以处理invokeAll 返回的期货。但是,如果Callables 之一抛出异常并终止其他线程,我希望invokeAll 立即返回。

使用execute 而不是invokeAll 会阻塞第一个future.get(),它不需要是引发执行的那个。

使用忙等待循环遍历所有期货并检查isDone()似乎也不是最好的方法。

【问题讨论】:

  • 您是否尝试过关闭 executos 服务并让它中断其他任务?如果那些其他任务不等待/读取,他们仍然可以不时检查线程中断标志

标签: java multithreading exception executorservice


【解决方案1】:

您可以使用更复杂的同步机制,例如锁存器、屏障或信号量,但请查看 ExecutorCompletionService。它是围绕ExecutorService 的轻量级包装器,允许您监听first 完成的任务。这是一个简单的例子:

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();

代码很简单。首先你用completionService 包裹executorService。以后你用它一个接一个地提交任务。最后一行很关键。它需要完成的第一个任务并尝试检索结果。如果抛出异常,会在这里重新抛出,用ExecutionException包裹:

try {
    completionService.take().get();
} catch (ExecutionException e) {
    e.getCause();       //this was thrown from task!
}

catch 块中,您可以以某种方式处理异常,例如取消剩余任务或关闭整个线程池。

当然,您可以拨打take() 十次,等待所有任务完成。只要至少完成一项任务,每次调用都会阻塞。

【讨论】:

  • 如果出现异常,您将如何终止其余线程?
  • @zaske:每个submit() 都返回Future&lt;T&gt;。如果遇到异常,您可以遍历所有期货并cancel() 它们。
  • @Tomasz Nurkiewicz - 但是完成服务 take 方法的调用者如何理解发生了异常?
  • @zaske:.get() 然后抛出一个 ExecutionException。
  • 为了能够重复使用线程池进行多次迭代,人们可能还想看看 ListeningExecutorService/ListenableFuture
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
  • 2011-06-25
  • 2019-01-06
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多