The difference has to do with the Executor
that is responsible for running the code. Each operator on CompletableFuture
generally has 3 versions.
thenApply(fn)
– runsfn
on a thread defined by theCompleteableFuture
on which it is called, so you generally cannot know where this will be executed. It might immediately execute if the result is already available.thenApplyAsync(fn)
– runsfn
on a environment-defined executor regardless of circumstances. ForCompletableFuture
this will generally beForkJoinPool.commonPool()
.thenApplyAsync(fn,exec)
– runsfn
onexec
.
In the end the result is the same, but the scheduling behavior depends on the choice of method.