0

When I execute thenApply method of a CompletableFuture, the execution of this method is happening in the ForkJoinPool thread, not on caller (main) thread. Why is it so? This result i.e using the fork join pool instead of caller thread is similar to when calling thenApplyAsync, so I want to understand the reason behind this behavior of thenApply

        System.out.println("hello world, CompletableFuturesRightHere");
        System.out.println("log1: " + Thread.currentThread().getName());

        CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(() -> {
            System.out.println("log-sA: " + Thread.currentThread().getName());
            return 40;
        }).thenApply( a ->  {
            System.out.println("log-tA: " + Thread.currentThread().getName());
            return a + 40;
        });

        System.out.println("log3: " + Thread.currentThread().getName());
        System.out.println("cf result: " + cf.get());

below is output of above code:

hello world, CompletableFuturesRightHere
log1: main
log-sA: ForkJoinPool.commonPool-worker-3
log3: main
log-tA: ForkJoinPool.commonPool-worker-3
cf result: 80

When I run the same code in jdoodle, the behavior is as expected.

samshers
  • 1
  • 6
  • 37
  • 84

1 Answers1

2

The CompletableFuture documentation states

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 covers both behaviors you describe; either, the original thread from the fork join pool is reused ("ForkJoinPool.commonPool-worker-3" in your output) for the following completion stage, or the calling thread is used after the previous stage finishes.

Using thenApplyAsync would be able to use a different thread from the common pool.

daniu
  • 14,137
  • 4
  • 32
  • 53
  • i did look at the method documentation, but thank for pointing out above point that is documented at class level. – samshers Mar 17 '23 at 06:37
  • `or by **any other** caller of a completion method.` <- would you mind to elaborate on this. It seems to point to more than just the caller (main) thread. – samshers Mar 17 '23 at 06:42
  • @samshers I understand it to mean "in any thread of the current call stack", ie if you do `CompletableFuture.supplyAsync().thenApplyAsync().thenApplyAsync().thenApply()`, the last call will be performed in either of the (up to) three threads used by the previous ones, but never a new one. But that's my interpretation, not an authoritative answer. – daniu Mar 17 '23 at 07:56
  • 3
    @samshers [this answer](https://stackoverflow.com/a/46062939/2711488) elaborates on the meaning of “any other caller of a completion method”. The takeaway is that using `thenApply` instead of `thenApplyAsync` implies *the least control* over the executing thread imaginable. – Holger Mar 17 '23 at 09:11