Почему ForkJoinPool использует ThreadPerTaskExecutor? - PullRequest
2 голосов
/ 12 апреля 2019

Мы запускаем приложение Akka на Java в среде с двумя процессорами, и мы наблюдали, что с каждым 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().

Итак, в нашем случае, когда у нас всего два процессора, ForkJoinPool вообще не используется. Вместо этого по умолчанию используется ThreadPerTaskExecutor. Я знаю, что мы можем переопределить это (мы делаем, и это вызывает значительное увеличение производительности). Но это заставляет меня задуматься, почему это так? Почему лучше начинать новый поток каждый раз, чем повторно использовать один из пула даже для одного процессора (не говоря уже о двух)? Почему это поведение по умолчанию ForkJoinPool?

1 Ответ

0 голосов
/ 12 апреля 2019

Если диспетчер имеет только один поток, и этот поток блокируется, блокируется и т. Д., Тогда вся система акторов останавливается.С потоками на задачу этого не произойдет.

...