2013-01-10 115 views
5

我使用Executors.newCachedThreadPool()invokeAllCallable列表来执行长时间运行的多线程处理。 我的主线程被阻止,直到所有线程完成,我可以处理由invokeAll返回的期货。但是,如果Callable中的一个抛出异常并终止其他线程,我会立即返回invokeAll只要有一个子线程抛出异常,就返回主线程

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

使用繁忙的等待来循环所有的期货,并检查isDone()似乎并不是最好的方式。

+0

您是否试过关闭executos服务并让它中断其他任务?如果这些其他任务不等待/读取,他们仍然可以每隔一段时间检查一次线程中断标志 – radai

回答

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

该代码非常简单。首先你用completionService包装executorService。之后你会用它来一个接一个地提交任务。最后一行是至关重要的。它会完成第一项任务并尝试检索结果。如果抛出一个异常,这将在这里再次抛出,包裹着ExecutionException

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

里面catch块,你能以某种方式处理异常,例如取消剩余的任务或关闭整个线程池。

当然,您可以通过拨打take()十次来完成所有任务。只要至少有一项任务完成,每个呼叫都会阻止。

+0

+1您赢得了这一个;-) – assylias

+0

如何在异常时终止其余线程? –

+0

@zaske:每个'submit()'返回'Future '。如果你遇到一个异常,你可以迭代所有的期货和'cancel()'它们。 –

相关问题