Ich habe eine Methode, die eine List
der Futures zurückgibt
List<Future<O>> futures = getFutures();
Jetzt möchte ich warten, bis entweder alle Futures erfolgreich verarbeitet wurden oder eine der Aufgaben, deren Ausgabe von einer Zukunft zurückgegeben wird, eine Ausnahme auslöst. Selbst wenn eine Aufgabe eine Ausnahme auslöst, macht es keinen Sinn, auf die anderen Zukünfte zu warten.
Einfacher Ansatz wäre zu
wait() {
For(Future f : futures) {
try {
f.get();
} catch(Exception e) {
//TODO catch specific exception
// this future threw exception , means somone could not do its task
return;
}
}
}
Aber das Problem hier ist, wenn zum Beispiel die 4. Zukunft eine Ausnahme auslöst, dann werde ich unnötig warten, bis die ersten 3 Futures verfügbar sind.
Wie kann man das lösen? Wird der Countdown in irgendeiner Weise helfen? Ich kann Future nicht verwenden, isDone
da das Java-Dokument dies sagt
boolean isDone()
Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
java
multithreading
future
user93796
quelle
quelle
ExecutionService
für jeden "Stapel" von Aufgaben eine Instanz erstellen, diese an ihn senden, dann den Dienst sofort herunterfahren undawaitTermination()
ihn vermutlich verwenden.CountDownLatch
wenn Sie den Körper aller Ihrer Futures in a eingewickelt habentry..finally
, um sicherzustellen, dass der Riegel ebenfalls dekrementiert wird.Antworten:
Sie können einen CompletionService verwenden , um die Futures zu erhalten, sobald sie bereit sind. Wenn einer von ihnen eine Ausnahme auslöst, brechen Sie die Verarbeitung ab. Etwas wie das:
Ich denke, Sie können sich weiter verbessern, um noch laufende Aufgaben abzubrechen, wenn einer von ihnen einen Fehler auslöst.
quelle
CompletionService
.Wenn Sie Java 8 verwenden , können Sie dies einfacher mit CompletableFuture und CompletableFuture.allOf tun , die den Rückruf erst anwenden , nachdem alle bereitgestellten CompletableFutures ausgeführt wurden.
quelle
Future
Instanzen haben, können Sie diese Methode nicht anwenden. Es ist nicht einfach,Future
in zu konvertierenCompletableFuture
.Verwenden Sie a
CompletableFuture
in Java 8quelle
Sie können einen ExecutorCompletionService verwenden . Die Dokumentation enthält sogar ein Beispiel für Ihren genauen Anwendungsfall:
Wichtig hierbei ist, dass ecs.take () die erste abgeschlossene Aufgabe erhält , nicht nur die erste eingereichte. Daher sollten Sie sie in der Reihenfolge erhalten, in der die Ausführung beendet ist (oder eine Ausnahme ausgelöst wird).
quelle
Wenn Sie Java 8 verwenden und
CompletableFuture
s nicht manipulieren möchten , habe ich ein Tool geschrieben, mit dem Sie Ergebnisse für einList<Future<T>>
Streaming abrufen können . Der Schlüssel ist, dass es dir verboten ist,map(Future::get)
wenn es wirft.Dies erfordert eine
AggregateException
, die wie C # funktioniertDiese Komponente fungiert genau wie die Task.WaitAll von C # . Ich arbeite an einer Variante, die das Gleiche tut wie
CompletableFuture.allOf
(äquivalent zuTask.WhenAll
)Der Grund, warum ich das getan habe, ist, dass ich Spring's verwende
ListenableFuture
und nicht portieren möchte,CompletableFuture
obwohl dies ein Standardweg istquelle
Wenn Sie eine Liste von CompletableFutures kombinieren möchten, können Sie dies tun:
Weitere Informationen zu Future & CompletableFuture finden Sie unter nützlichen Links:
1. Future: https://www.baeldung.com/java-future
2. CompletableFuture: https://www.baeldung.com/java-completablefuture
3. CompletableFuture: https : //www.callicoder.com/java-8-completablefuture-tutorial/
quelle
Vielleicht würde dies helfen (nichts würde durch rohen Thread ersetzt, ja!). Ich schlage vor, jeden
Future
Kerl mit einem getrennten Thread auszuführen (sie gehen parallel). Wenn dann einer der Fehler auftritt, signalisiert dies nur dem Manager (derHandler
Klasse).Ich muss sagen, dass der obige Code fehlerhaft wäre (nicht überprüft), aber ich hoffe, ich könnte die Lösung erklären. Bitte probieren Sie es aus.
quelle
quelle
Der CompletionService nimmt Ihre Callables mit der .submit () -Methode und Sie können die berechneten Futures mit der .take () -Methode abrufen.
Eine Sache, die Sie nicht vergessen dürfen, ist das Beenden des ExecutorService durch Aufrufen der .shutdown () -Methode. Sie können diese Methode auch nur aufrufen, wenn Sie einen Verweis auf den Executor-Service gespeichert haben. Stellen Sie daher sicher, dass Sie einen behalten.
Beispielcode - Für eine feste Anzahl von Arbeitselementen, die parallel bearbeitet werden sollen:
Beispielcode - Für eine dynamische Anzahl von Arbeitselementen, die parallel bearbeitet werden sollen:
quelle
Ich habe eine Utility-Klasse, die Folgendes enthält:
Sobald Sie das haben, können Sie mit einem statischen Import einfach auf alle Futures wie diese warten:
Sie können auch alle Ergebnisse wie folgt sammeln:
Ich besuche nur meinen alten Beitrag und bemerke, dass du noch einen Kummer hattest:
In diesem Fall besteht die einfache Lösung darin, dies parallel zu tun:
Auf diese Weise wird die erste Ausnahme, obwohl sie die Zukunft nicht aufhalten wird, die forEach-Anweisung wie im seriellen Beispiel unterbrechen, aber da alle parallel warten, müssen Sie nicht warten, bis die ersten 3 abgeschlossen sind.
quelle
quelle