2013-07-02 14 views
6

Mam zestaw Futures utworzony przez przesłanie Callable s do Executor. Pseudo kod:Limit czasu w oczekiwaniu na zakończenie partii kontraktów Futures?

for all tasks 
    futures.add(executor.submit(new callable(task))) 

Teraz chciałbym, aby wszystkie futures czekały najwyżej n sekund, aż wszystkie zostaną zakończone. Wiem, że mogę zadzwonić pod numer Future#get(timeout), ale jeśli zadzwonię do niego sekwencyjnie dla wszystkich moich przyszłości w pętli, zaczynają się dodawać timery. pseudokod:

for all futures 
    future.get(timeout) 

get bloki z timeout aż do wyniku jest gotowy. Dlatego też, jeśli pierwszy kończy się tuż przed przekroczeniem limitu czasu, a drugi kończy się tuż przed przekroczeniem limitu czasu, a więc cały czas wykonywania wynosi co najwyżej number of futures * timeout zamiast timeout.

Dlatego szukam metody, która akceptuje listę Future s i limit czasu, działa wszystko równolegle, a następnie zwraca kolekcję przyszłych wyników. Jakieś pomysły?

+0

Nie jest to całkowicie jasne. Co chcesz zrobić z zadaniami, które nie zakończyły się po upływie czasu oczekiwania? Czy chcesz je anulować lub zezwolić na kontynuację? –

+0

Powinny one zostać anulowane. Poza tym muszę wiedzieć, które zostały zakończone, a które nie. Sądzę, że mógłbym powtórzyć raz jeszcze o przyszłości i przywołać 'isDone' na wszystkich z nich. –

Odpowiedz

5

Można użyć ExecutorService.invokeAll:

Wykonuje podane zadania, zwracając listę Futures posiadających statusu i rezultatów, gdy wszystkie kompletne lub limit czasu upłynie, cokolwiek dzieje się w pierwszej kolejności. Future.isDone() jest prawdziwe dla każdego elementu zwróconej listy. Po powrocie zadania, które nie zostały zakończone, są anulowane. Zauważ, że ukończone zadanie mogło zostać zakończone normalnie lub przez zgłoszenie wyjątku. Wyniki tej metody są niezdefiniowane, jeśli dana kolekcja jest modyfikowana podczas tej operacji.


Jeśli masz już Future s, które trzeba monitorować i nie może korzystać invokeAll, można po prostu mierzyć timeout siebie. Pseudo-kod:

long endTime = System.currentTimeMillis() + timeoutMS; 
for(f : futures) 
    f.get(Math.max(0, endTime - System.currentTimeMillis()), TimeUnit.MILLISECONDS); 

W ten sposób każda z przyszłych okresów będzie trwać co najwyżej do końca czasu oczekiwania.

+0

'ExecutorService.invokeAll' brzmi jak to, co jestem po, dzięki. Dla wszystkich przyszłości, które nie zostały ukończone w czasie 'isCancelled == true', right (tak interpretuję Javadoc)? Jak dowiem się, czy "Przyszłość" zakończyła się wyjątkiem? "Zauważ, że ukończone zadanie mogło zostać zakończone albo normalnie, albo przez zgłoszenie wyjątku" - to trudne ... –

+1

@ MarcelStör Tak, transakcje, które nie zostały zakończone, są anulowane ('isCancelled() == true'). Następnie określasz, co stało się z 'Przyszłością' kiedy nazywasz to' 'get()'] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html# get% 28% 29) (po zwrocie 'invokeAll'). Jeśli 'get' zgłasza' CancellationException', wiesz, że zostało anulowane. Jeśli wyrzuci 'ExecutionException', oznacza to' Przyszłość' zakończoną z wyjątkiem, a wyjątek jest dostępny poprzez 'ExecutionException.getCause()'. –

Powiązane problemy