CompletableFuture 的奇怪行为

The Strange behavior of CompletableFuture

为什么下面的代码不打印I just woke up

    import java.util.concurrent.CompletableFuture;
    public class CompletableFutureTest {
        public static void main(String[] args) {
            CompletableFuture completableFuture = CompletableFuture.runAsync(()->{
                try {
                    Thread.sleep(4000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("I just woke up.");
            });
            System.out.println("I am main");
        }
    }

下面给出的代码打印 I just woke up

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture completableFuture = CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I just woke up.");
        }, executorService);
        executorService.shutdown();
        System.out.println("I am main");
    }
}

这两种代码之间可能存在的显着差异是,第二个代码示例将单线程池带入 runAsync 方法,而第一个代码不使用任何参数,即它使用 ForkJoin 池。 请帮我弄清楚 I just woke up 没有在第一个程序

中打印的原因

来自ForkJoinPool

...All worker threads are initialized with Thread.isDaemon() set true.

来自Executors.defaultThreadFactory

...Each new thread is created as a non-daemon thread.

来自Thread.setDaemon

...The Java Virtual Machine exits when the only threads running are all daemon threads.

在第一种情况下,线程来自 ForkJoinPool.commonPool,因此它是守护进程。
在第二种情况下,线程是使用 Executors.defaultThreadFactory 创建的,non-daemon.

也是如此

这解释了不同的行为。