Search code examples
javamultithreadingjava.util.concurrentcompletable-future

CompletableFuture thenApply is running in seperate thread not on caller thread?


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.


Solution

  • 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.