CompletableFuture não está sendo executado. Se eu usar o pool ExecutorService, seu trabalho conforme o esperado, mas não com o pool comum forkJoin padrão

Eu estou tentando executar a seguinte classe está sendo finalizada sem executar o CompletableFuture.

public class ThenApplyExample {

public static void main(String[] args) throws Exception {
    //ExecutorService es = Executors.newCachedThreadPool();
    CompletableFuture<Student> studentCompletableFuture = CompletableFuture.supplyAsync(() -> {

        try {

            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 3;
    })// If I put executorservice created n commented above, programme work as expected.
            .thenApply(i -> {

                for (int j = 0; j <= i; j++) {
                    System.out.println("Inside first then apply");
                }
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("First then apply is finished");
                return ++i;
            })
            .thenApply(i -> {
                System.out.println("Inside 2nd then apply");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Inside 2nd then apply stopped");

                return i++;
            })
            .thenApply(i -> {
                System.out.println("Inside 3nd then apply");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Inside 3nd then apply stopped");
                return "The i is ::: " + i;
            })
            .thenApply(s -> Student.builder().id(1).name(s).address("Some address").build());
    System.out.println("Executing..");
    System.out.println("Executing..");
    System.out.println("Executing..");
    System.out.println("Executing..");
    System.out.println("Executing..");

    //es.shutdown();
}
} 

A saída que estou recebendo é

Executing..
Executing..
Executing..
Executing..
Executing..

Considerando que a produção esperada é

Executing..
Executing..
Executing..
Executing..
Executing..
Inside first then apply
Inside first then apply
Inside first then apply
Inside first then apply
First then apply is finished
Inside 2nd then apply
Inside 2nd then apply stopped
Inside 3nd then apply
Inside 3nd then apply stopped

Nota : No programa acima, não estou usando studentCompletableFuture.get (). Eu não quero usá-lo, uma vez que bloqueia o código.

Se eu adicionarstudentCompletableFuture.get () no final do programa, ele funciona conforme o esperado ou se eu adicionar oexecutorservice no segundo argumento supplyAsync (verifique o comentário no programa), ele funciona novamente conforme o esperado.

Minha pergunta é por que ele está sendo finalizado quando o programa usa o pool comum do ForkJoin padrão?

questionAnswers(1)

yourAnswerToTheQuestion