为什么ForkJoinPool使用ThreadPerTaskExecutor?

时间:2019-04-12 10:18:29

标签: java concurrency akka completable-future forkjoinpool

我们在Java上的两个CPU环境中运行Akka应用程序,我们观察到每个tell都会启动一个新线程,而不是将其从池中取出。 Akka默认调度程序使用ForkJoinPool作为默认执行程序。在CompletableFuture代码中,有以下逻辑:

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


private static final Executor asyncPool = useCommonPool ?
    ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

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

commonPoolParallelism的值来自Runtime.getRuntime().availableProcessors() - 1(如果未指定JVM属性)-ForkJoinPool.makeCommonPool()

因此,在我们的情况下-我们只有两个CPU-根本没有使用ForkJoinPool。默认情况下,它使用ThreadPerTaskExecutor代替。我知道我们可以覆盖它(这样做会导致性能显着提高)。但这使我想知道为什么呢?为什么每次都启动一个新线程要比从一个池中重用一个线程更好,甚至对于一个CPU也是如此(更不用说两个线程了)?为什么这是ForkJoinPool的默认行为?

1 个答案:

答案 0 :(得分:0)

如果调度程序只有一个线程,并且该线程被阻塞,死锁等,则整个actor系统都会停止运行。如果每个任务都有线程,那将不会发生。