completeablefuture join vs get

90

Was ist der Unterschied zwischen CompletableFuture.get()und CompletableFuture.join()?

Unten ist mein Code:

List<String> process() {

    List<String> messages = Arrays.asList("Msg1", "Msg2", "Msg3", "Msg4", "Msg5", "Msg6", "Msg7", "Msg8", "Msg9",
            "Msg10", "Msg11", "Msg12");
    MessageService messageService = new MessageService();
    ExecutorService executor = Executors.newFixedThreadPool(4);

    List<String> mapResult = new ArrayList<>();

    CompletableFuture<?>[] fanoutRequestList = new CompletableFuture[messages.size()];
    int count = 0;
    for (String msg : messages) {
        CompletableFuture<?> future = CompletableFuture
                .supplyAsync(() -> messageService.sendNotification(msg), executor).exceptionally(ex -> "Error")
                .thenAccept(mapResult::add);

        fanoutRequestList[count++] = future;
    }

    try {
        CompletableFuture.allOf(fanoutRequestList).get();
      //CompletableFuture.allOf(fanoutRequestList).join();
    } catch (InterruptedException | ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return mapResult.stream().filter(s -> !s.equalsIgnoreCase("Error")).collect(Collectors.toList());
}

Ich habe es mit beiden Methoden versucht, aber ich sehe keinen Unterschied im Ergebnis.

Nomeswaran
quelle
9
get()erfordert, dass Sie geprüfte Ausnahmen abfangen. Sie sollten den Unterschied bemerken, wenn Sie von get()nach wechseln join(), da Sie sofort einen Compilerfehler erhalten, der besagt, dass weder InterruptedExceptionnoch ExecutionExceptionin den tryBlock geworfen werden .
Holger
5
@ holi-java: join()kann nicht unterbrochen werden.
Holger
@ Holger ja, Sir. Ich habe festgestellt, dass ich die Aufgabe nicht unterbrechen kann.
Holi-Java
8
Gut getexistiert, weil CompletableFutureimplementiert die FutureSchnittstelle, die es vorschreibt. join()höchstwahrscheinlich wurde eingeführt, um zu vermeiden, dass beim Kombinieren von Futures geprüfte Ausnahmen in Lambda-Ausdrücken abgefangen werden müssen. In allen anderen Anwendungsfällen können Sie alles verwenden, was Sie bevorzugen.
Holger
1
Ist es wirklich sinnvoll, join oder get als beide Block im Thread zu verwenden? Können wir dies nicht stattdessen asynchron machen, indem wir andere Kompositionsmethoden verwenden, um eine Kette von asynchronen Funktionen zu erstellen? Natürlich hängt es von der Funktionalität ab. Aber wenn beispielsweise eine Servicemethode im Frühjahr von der Controller-Methode aufgerufen wird, die eine vollständig abschließbare Zukunft zurückgibt, ist es sinnvoller, die Servicemethode get überhaupt nicht aufzurufen oder sich ihr anzuschließen.
Shailesh Vaishampayan

Antworten:

102

Der einzige Unterschied besteht darin, wie Methoden Ausnahmen auslösen. get()wird in der FutureSchnittstelle als deklariert

V get() throws InterruptedException, ExecutionException;

Die Ausnahmen sind beide geprüfte Ausnahmen, was bedeutet, dass sie in Ihrem Code behandelt werden müssen. Wie Sie in Ihrem Code sehen können, fragte ein automatischer Codegenerator in Ihrer IDE, ob Sie in Ihrem Namen einen Try-Catch-Block erstellen sollen.

try {
  CompletableFuture.allOf(fanoutRequestList).get() 
} catch (InterruptedException | ExecutionException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

Die join()Methode löst keine geprüften Ausnahmen aus.

public T join()

Stattdessen wird eine ungeprüfte CompletionException ausgelöst. Sie benötigen also keinen Try-Catch-Block, sondern können die exceptionally()Methode bei Verwendung der Disscused- List<String> processFunktion vollständig nutzen

CompletableFuture<List<String>> cf = CompletableFuture
    .supplyAsync(this::process)
    .exceptionally(this::getFallbackListOfStrings) // Here you can catch e.g. {@code join}'s CompletionException
    .thenAccept(this::processFurther);

Beides get()und die join()Implementierung finden Sie hier

Dawid Wróblewski
quelle