当公共池不支持并行级别 >= 2 时,让 CompletableFuture 为任务创建单独的线程的意图

问题描述 投票:0回答:1

CompletableFuture
的 Java 文档指出:

所有没有显式 Executor 参数的异步方法都使用 ForkJoinPool.commonPool() 执行(除非它不支持至少两个并行级别,在这种情况下,将创建一个新线程来运行每个任务)

决定为每个任务创建一个线程的原因是什么?为什么他们不选择创建一个至少有 2 个工作线程的池,或者为什么

commonPool()
返回的执行器没有至少 2 个工作线程?

为每个任务创建一个线程对我来说效率很低。

java java.util.concurrent
1个回答
0
投票

TL;DR:

commonPool
可以是同步的。它可以在调用
.join()
时直接在调用 join 的线程上执行任务,而不是安排任务在后台线程上运行。这种同步执行语义很容易导致死锁,从而违反异步方法的约定。
CompletableFuture
通过生成新线程来解决潜在的同步执行问题。

注意:具有一个后台线程的

commonPool
和没有后台线程的同步
commonPool
都报告
parallelism
1
。仅在后一种情况下才需要线程 hack,但没有尝试区分这两种情况。

参考:

此更改是在以下提交中进行的:

8020435:CompletableFuture/Basic.java 在单核机器上失败

https://github.com/openjdk/jdk/commit/b1a10b8ed7bedb27ae25341602319a11a1225ee7

当时的代码对于并行语义有什么说明:

公共池并行性。为了更简单的使用和管理 当公共池线程被禁用时,我们允许底层 common.parallelism 字段为零,但在这种情况下仍然报告 并行度为 1 以反映最终的调用者运行机制。

https://github.com/openjdk/jdk/blob/b1a10b8ed7bedb27ae25341602319a11a1225ee7/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java#L1100-L1106

© www.soinside.com 2019 - 2024. All rights reserved.