我们在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
的默认行为?
答案 0 :(得分:0)
如果调度程序只有一个线程,并且该线程被阻塞,死锁等,则整个actor系统都会停止运行。如果每个任务都有线程,那将不会发生。