8

I am trying to understand the working of CompletableFuture from Java 8. Below code works as expected

CompletableFuture.supplyAsync(() -> {
    System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
    return "str";
}).thenApply(str -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    return str;
}).thenApply(str1 -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    return str1;
}).thenAccept(str3 -> {
    System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
});
System.out.println("Thread name " + Thread.currentThread().getName());

Output:

supplyAsync Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name main
thenApply Thread name main
thenAccept Thread name main
Thread name main

But when I put in some computation, it doesn't work as expected please correct me if I am missing something.

CompletableFuture.supplyAsync(() -> {
    System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return "str";
}).thenApply(str -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return str;
}).thenApply(str1 -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return str1;
}).thenAccept(str3 -> {
    System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
});

System.out.println("Thread name " + Thread.currentThread().getName());

Output is:

supplyAsync Thread name ForkJoinPool.commonPool-worker-1
Thread name main

I agree that I am not joining the child thread to main thread. My understanding is child thread should print the statements independently of main thread. The question is why is it not printing at all.

  • Possible duplicate of [How to use CompletableFuture in java 8 to start an async task and let main thread finish and exit](https://stackoverflow.com/questions/48573856/how-to-use-completablefuture-in-java-8-to-start-an-async-task-and-let-main-threa) – Didier L Dec 14 '18 at 09:10
  • There might be a better duplicate but I cannot find it right now. – Didier L Dec 14 '18 at 09:23

2 Answers2

4

Explanation

You're not joining the child thread ForkJoinPool.commonPool-worker-1 to the main thread. So it gets killed once thread main finishes.

Solution

Try calling .join() on your completable future at some point in your code. Note that this method is blocking the main thread. So the execution after the join point will be suspended until the child thread finishes its execution.

CompletableFuture.supplyAsync(() -> {
    System.out.println("=> supplyAsync Thread name " + Thread.currentThread().getName());
    // ...
}).thenApply(str -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    // ...
}).thenApply(str1 -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    // ...
}).thenAccept(str3 -> {
    System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
    // ...
}).join()

Will print:

supplyAsync Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name ForkJoinPool.commonPool-worker-1
thenAccept Thread name ForkJoinPool.commonPool-worker-1
Thread name main

If you want the last System.out.println(...) not depend from execution of the child thread then assign your CompletableFuture to a variable and join it in the very end of main:

CompletableFuture<Void> future = CompletableFuture.supplyAsync(...) ... // 

System.out.println("Thread name " + Thread.currentThread().getName());

future.join();    
ETO
  • 6,970
  • 1
  • 20
  • 37
  • Thanks for the answer. In the first example I have not used join still its working properly thats what confusing me. – Vishwanath Joshi Dec 14 '18 at 08:45
  • 7
    @VishwanathJoshi in the first example, you ran by pure luck. It’s entirely unpredictable whether the supplier provided to `supplyAsync` completes before the next `thenApply` call or not. Run it multiple times and you may get different results. – Holger Dec 14 '18 at 11:39
  • @Holger I have a similar code with only one call to `thenApply()` after a call to `allOf()` when I add `System.out` statement it doesn't execute, but works well everytime when the print statements are removed. what's the explanation for this? – Mr.Cat Nov 11 '20 at 19:51
  • 2
    @Mr.Cat I suggest opening a new question with the necessary details – Holger Nov 12 '20 at 07:40
0

My understanding is child thread should print the statements independently of main thread.

Your understanding is incorrect.

Per the documentation:

Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.

This does not insist that the dependent completion be executed by the thread that completes the async operation, it merely allows it.

Still, I concur with the other answer which says that you should arrange to have the main routine not exit until the chain of computations is complete.

user16632363
  • 1,050
  • 3
  • 6