Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Completablefuture doesnot complete on exception

I'm kinda new to using CompletableFuture API and I have a question regarding usage of allOf. From what I read, completable-future should be in complete state and allOf logic should be executed when all associated futures complete, including completed-exceptionally. But here's my smaple code for which allOf block never gets executed -

public static void test() {
    CompletableFuture<String> r1 = CompletableFuture.supplyAsync(() -> {
        try{
            Thread.sleep(1000);
            throw new RuntimeException("blahh !!!");
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    });

    CompletableFuture<String> r2 = CompletableFuture.supplyAsync(() -> "55");
    CompletableFuture<String> r3 = CompletableFuture.supplyAsync(() -> "56");
    CompletableFuture.allOf(r1, r2, r3).thenRun(() -> { System.out.println(Thread.currentThread()+" --- End."); });
    Stream.of(r1, r2, r3).forEach(System.out::println);


    try{
        System.out.println(Thread.currentThread()+" --- SLEEPING !!!");
        Thread.sleep(3000);
        System.out.println(Thread.currentThread()+" --- DONE !!!");
    } catch (Exception e) {
        //e.printStackTrace();
    }
    Stream.of(r1, r2, r3).forEach(System.out::println);
}
like image 685
V1666 Avatar asked Mar 18 '26 04:03

V1666


1 Answers

The problem is not that your allOf CompletableFuture never completes. It does.

What causes your code not to run is thenRun's expectation:

Returns a new CompletionStage that, when this stage completes normally, executes the given action. See the CompletionStage documentation for rules covering exceptional completion.

You probably already know that when one of allOf's futures completes exceptionally, the resulting future also completes exceptionally:

Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete. If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture also does so, with a CompletionException holding this exception as its cause.

In short, don't use thenRun if you want to run an action on your allOf future irrespective of how it comples. As an alternative, you can use whenComplete:

CompletableFuture.allOf(r1, r2, r3)
        .whenComplete((a, ex) -> System.out.println(Thread.currentThread() + " --- End."));

You can also use a combination of thenRun + exceptionally, one of which will run:

CompletableFuture<Void> all = CompletableFuture.allOf(r1, r2, r3);
all.thenRun(() -> {
    System.out.println(Thread.currentThread() + " --- End.");
});
all.exceptionally(ex -> {
    System.out.println(ex);
    return null;
});
like image 111
ernest_k Avatar answered Mar 19 '26 16:03

ernest_k



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!