2013-01-10 114 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()'它們。 –

相關問題