2013-01-10 11 views
5

Używam Executors.newCachedThreadPool() i invokeAll z Listą Callable s do długotrwałego przetwarzania wielowątkowego. Mój główny wątek jest blokowany do czasu zakończenia wszystkich wątków i mogę przetworzyć transakcje Futures zwrócone przez invokeAll. Chciałbym jednak, aby invokeAll natychmiast powrócił, jeśli jeden z Callable s rzuci wyjątek i zakończy inne wątki.Powróć do głównego wątku, jak tylko jeden wątek podrzędny zgłasza wyjątek

Używanie execute zamiast invokeAll spowoduje zablokowanie pierwszego future.get(), który nie musi być tym, który rzuca wykonanie.

Korzystanie z zajęty czekanie na pętli przez wszystkie futures i sprawdzanie isDone() wydaje się również nie być najlepszym sposobem.

+0

Czy próbowałeś wyłączyć usługę execos i przerywać inne zadania? jeśli te inne zadania nie czekają/nie czytają, mogą nadal sprawdzać flagę przerwania wątku co jakiś czas – radai

Odpowiedz

6

Można użyć bardziej złożonych mechanizmów synchronizacji, takich jak zatrzaski, bariery lub semafory, ale spójrz na ExecutorCompletionService. Jest to lekkie opakowanie o rozmiarze ExecutorService, które umożliwia odsłuchanie ukończonego zadania . Oto krótki przykład:

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

Kod jest dość prosty. Najpierw zawiń executorService z completionService. Później używasz go do przesyłania zadań jeden po drugim. Najważniejsza jest ostatnia linia. Wykonuje pierwsze zadanie, które zakończyło się i próbuje pobrać wynik. Jeśli jest rzucony wyjątek, zostanie on rethrown tutaj, owinięte ExecutionException:

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

Wewnątrz catch blok można jakoś obsłużyć wyjątek, na przykład anulowanie pozostałych zadań lub wyłączenie całej puli wątków.

Oczywiście możesz poczekać, aż wszystkie zadania zakończą się, dzwoniąc pod numer take() dziesięć razy. Każde połączenie zostanie zablokowane, o ile zostało zakończone co najmniej jedno zadanie.

+0

+1, wygrywasz tę ;-) – assylias

+0

A jak zakończysz resztę wątków po wyjściu? –

+0

@zaske: każdy 'submit()' zwraca 'Future '. Jeśli napotkasz wyjątek, możesz po prostu powtórzyć wszystkie transakcje futures i je anulować(). –

Powiązane problemy