V1666
V1666

Reputation: 205

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

Upvotes: 2

Views: 4128

Answers (1)

ernest_k
ernest_k

Reputation: 45319

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

Upvotes: 3

Related Questions