2013-01-10 13 views
5

sto usando Executors.newCachedThreadPool() e invokeAll con una lista di Callable s per fare l'elaborazione di lunga durata multithread. Il mio thread principale è bloccato fino a quando tutti i thread sono finiti e posso elaborare i Futures restituiti da invokeAll. Vorrei comunque che invokeAll restituisca immediatamente se uno dei Callable s genera un'eccezione e termina gli altri thread.Ritorna al thread principale non appena uno thread figlio genera un'eccezione

Utilizzando execute anziché invokeAll bloccherebbe il primo future.get() che deve non essere quello che genera l'execption.

Utilizzo occupato in attesa di scorrere tutti i futures e controllo isDone() sembra non essere il modo migliore neanche.

+0

hai provato a chiudere il servizio di esecuzione e interromperlo? se quegli altri compiti non aspettano/leggono possono ancora controllare il flag di interruzione del thread ogni tanto – radai

risposta

6

È possibile utilizzare meccanismi di sincronizzazione più complessi come latch, barriere o semafori, ma dare un'occhiata a ExecutorCompletionService. È un involucro leggero intorno al ExecutorService che ti consente di ascoltare la prima attività completata. Ecco un breve esempio:

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

Il codice è piuttosto semplice. Per prima cosa avvolgi lo executorService con completionService. Più tardi lo usi per inviare compiti uno dopo l'altro. L'ultima riga è cruciale. Prende la prima attività completata e tenta di recuperare il risultato. Se lanciata un'eccezione, sarà rilanciati qui, avvolto con ExecutionException:

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

All'interno catch blocco è possibile in qualche modo gestire l'eccezione, per esempio annullare le attività rimanenti o chiudere l'intero pool di thread.

Ovviamente sei libero di aspettare che tutte le attività finiscano chiamando lo take() dieci volte. Ogni chiamata verrà bloccata finché è terminata almeno un'attività.

+0

+1 tu vinci questo ;-) – assylias

+0

E come terminerai il resto dei thread su eccezione? –

+0

@zaske: ogni 'submit()' restituisce 'Future '. Se incontri un'eccezione, puoi semplicemente ripetere tutti i futures e 'cancel()' loro. –