Given:
public class Test
{
public static void main(String[] args)
{
int nThreads = 1;
Executor e = Executors.newFixedThreadPool(nThre
The thenComposeAsync method places a new task for your executor that grabs the single thread and waits for your Task 2 to complete. But this one has no more threads to run. You can instead use thenCompose method that executes in the same thread as Task 1 to avoid the deadlock.
One thread is executing Task 1 and Task 2 and the second one is taking care of composing the results of the two.
Note: CompletableFuture(s) work best with a ForkJoinPool that is more efficient in processing tasks that spawn new tasks. The default ForkJoinPool was added in Java 8 for this purpose and is used by default if you don't specify an executor to run your tasks.
Here is a good presentation about where these new features shines and how they work: Reactive Programming Patterns with Java 8 Futures.