CompletableFuture使用之双核以下CPU要自定义线程池

在CPU核心数小于两核的机器上使用CompletableFuture时要注意,最好自定义线程池,否则会降级成新建线程,引发不必要的问题。

通过CompletableFuture.runAsync方法的源码可以看出,如果不提供线程池入参,则默认使用的是CompletableFuture.ASYNC_POOL这个线程池。

private static final boolean USE_COMMON_POOL =
        (ForkJoinPool.getCommonPoolParallelism() > 1);

/**
 * Default executor -- ForkJoinPool.commonPool() unless it cannot
 * support parallelism.
 */
private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

当ForkJoinPool的并行度大于1时,才会使用ForkJoinPool.commonPool(),否则使用的是ThreadPerTaskExecutor

static final class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        Objects.requireNonNull(r);
        new Thread(r).start();
    }
}

而ThreadPerTaskExecutor是一个虚假的线程池,每次都是直接new一个线程执行任务的,而坑就在这里。因为ForkJoinPool的并行度默认是等于机器的CPU核心数-1,所以当在双核CPU的机器环境下执行时,就会导致每次都是新建线程执行任务。


觉得内容还不错?打赏个钢镚鼓励鼓励!!👍