2013-07-02 14 views
6

Ich habe eine Reihe von Futures erstellt durch Übermittlung Callable s an eine Executor. Pseudo-Code:Timeout während des Wartens auf die Fertigstellung eines Stapels von Futures?

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

Jetzt möchte ich alle Futures warten höchstens n Sekunden bis alles abgeschlossen. Ich weiß, ich kann Future#get(timeout) anrufen, aber wenn ich das sequenziell für alle meine Zukünfte in einer Schleife rufe, fangen die Zeitpunkte an, sich zu addieren. Pseudo-Code:

for all futures 
    future.get(timeout) 

get Blöcke mit einem Timeout, bis das Ergebnis ist fertig. Wenn daher der erste Vorgang kurz vor dem Timeout abgeschlossen wird und der zweite auch kurz vor dem Timeout abgeschlossen wird, ist die gesamte Ausführungszeit höchstens number of futures * timeout statt timeout.

Daher suche ich nach einer Methode, die eine Liste von Future s und ein Timeout akzeptiert, läuft alle parallel und gibt dann eine Sammlung von zukünftigen Ergebnissen. Irgendwelche Ideen?

+0

Dies ist nicht ganz klar. Was möchten Sie mit den Tasks machen, die nach Ablauf des Timeouts noch nicht abgeschlossen sind? Möchten Sie, dass sie storniert werden oder fortgeführt werden dürfen? –

+0

Sie sollten abgebrochen werden. Außerdem muss ich irgendwie wissen, welche fertig waren und welche nicht. Ich schätze, dafür könnte ich noch einmal über die Zukunft iterieren und auf allen von ihnen 'isDone' aufrufen. –

Antwort

5

können Sie ExecutorService.invokeAll verwenden:

Führt die gestellten Aufgaben, um eine Liste von Futures Rückkehr ihren Status und die Ergebnisse zu halten, wenn alle vollständigen oder das Timeout abläuft, je nachdem, was zuerst eintritt. Future.isDone() gilt für jedes Element der zurückgegebenen Liste. Bei der Rückkehr werden Aufgaben, die nicht abgeschlossen wurden, storniert. Beachten Sie, dass eine abgeschlossene Aufgabe normal oder durch Auslösen einer Ausnahme beendet werden konnte. Die Ergebnisse dieser Methode sind nicht definiert, wenn die angegebene Sammlung geändert wird, während diese Operation ausgeführt wird.


Wenn Sie bereits Future s haben, die Sie überwachen müssen und können invokeAll nicht verwenden, können Sie einfach das Timeout selbst messen. Pseudocode:

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

Auf diese Weise geben Sie jeder Zukunft höchstens die Dauer, die bis zum Erreichen der Zeitüberschreitung übrig ist.

+0

'ExecutorService.invokeAll' klingt nach dem, wonach ich bin, danke. Für alle Futures, die nicht rechtzeitig fertiggestellt wurden: isCancelled == true', right (so interpretiere ich Javadoc)? Wie würde ich herausfinden, ob eine 'Zukunft' mit Ausnahme abgeschlossen ist? "Beachten Sie, dass eine abgeschlossene Aufgabe entweder normal oder durch Auslösen einer Ausnahme beendet werden konnte" - das ist schwierig ... –

+1

@ MarcelStör Ja, Futures, die nicht abgeschlossen wurden, werden abgebrochen ('isCancelled() == true'). Sie bestimmen dann, was mit einem 'Future' passiert ist, wenn Sie es [' get() '] nennen (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html#) get% 28% 29) (nachdem 'invokeAll 'zurückkommt). Wenn 'get'' 'CancellationException' auslöst, wissen Sie, dass es abgebrochen wurde. Wenn es "ExecutionException" auslöst, bedeutet dies, dass das 'Future' mit einer Ausnahme abgeschlossen ist und die Ausnahme über' ExecutionException.getCause() 'zugänglich ist. –

Verwandte Themen