CompleteFuture Join vs Get

91

Jaka jest różnica między CompletableFuture.get()i CompletableFuture.join()?

Poniżej znajduje się mój kod:

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

Próbowałem z obiema metodami, ale nie widzę różnicy w wyniku.

Nomeswaran
źródło
9
get()wymaga wyłapania zaznaczonych wyjątków. Powinieneś zauważyć różnicę po zmianie z get()na join(), ponieważ natychmiast otrzymasz błąd kompilatora mówiący, że ani InterruptedExceptionnie ExecutionExceptionsą wyrzucane w trybloku.
Holger
5
@ holi-java: join()nie można przerwać.
Holger
@ Holger tak, proszę pana. Okazało się, że nie mogę przerwać zadania.
holi-java
8
Dobrze getistnieje, ponieważ CompletableFutureimplementuje Futureinterfejs, który to narzuca. join()najprawdopodobniej została wprowadzona, aby uniknąć konieczności wyłapywania sprawdzonych wyjątków w wyrażeniach lambda podczas łączenia futures. We wszystkich innych przypadkach możesz swobodnie używać tego, co wolisz.
Holger
1
Czy naprawdę ma sens używanie funkcji join lub get jako obu bloków w wątku? Nie możemy zamiast tego uczynić tego asynchronicznym, używając innych metod kompozycji, aby utworzyć łańcuch funkcji asynchronicznych. W rzeczywistości zależy to od funkcjonalności. Ale w przypadku np. Metody serwisowej wywoływanej wiosną metodą kontrolera zwracającej kompletną przyszłość bardziej sensownym jest nie wywoływanie metody usługi get lub join w ogóle.
Shailesh Vaishampayan

Odpowiedzi:

105

jedyną różnicą jest sposób, w jaki metody zgłaszają wyjątki. get()jest zadeklarowana w Futureinterfejsie jako

V get() throws InterruptedException, ExecutionException;

Wyjątki są wyjątkami zaznaczonymi, co oznacza, że ​​muszą być obsługiwane w kodzie. Jak widać w Twoim kodzie, automatyczny generator kodu w Twoim IDE zapytał, czy utworzyć blok try-catch w Twoim imieniu.

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

join()Metoda nie rzucać sprawdzonych wyjątków.

public T join()

Zamiast tego zgłasza niesprawdzony CompletionException. Więc nie potrzebujesz bloku try-catch, a zamiast tego możesz w pełni wykorzystać exceptionally()metodę podczas korzystania z List<String> processfunkcji rozproszonej

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

Możesz znaleźć oba get()i join()implementację tutaj

Dawid Wróblewski
źródło