【问题标题】:CompletableFuture multi-threaded, single thread concurrent, or both?CompletableFuture 多线程、单线程并发,还是两者兼而有之?
【发布时间】:2025-12-12 12:55:02
【问题描述】:

我刚开始研究 Java 的 CompletableFuture,有点困惑这是真正的异步(即同时在一个线程上运行)还是跨越多个线程(并行)。

例如,假设我想进行 1000 次不同的服务调用。进一步假设每个服务调用都可以异步进行。使用 CompletableFuture 时,JVM 会创建 1000 个单独的线程(假设 JVM 允许这么多线程),还是在一个线程中执行所有这些请求?还是两者兼而有之?使用一些线程来异步执行这些请求?

我想做的是这样的(在 Python 中): https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html

有没有办法在 Java 中的同一个线程上异步执行多个请求/操作?

【问题讨论】:

    标签: java multithreading concurrency completable-future


    【解决方案1】:

    正如javadoc中解释的那样

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

    因此使用了线程池,可以是隐式的(除非您有一个单核机器,在这种情况下线程不会被池化)或显式的。在您的情况下,您可以通过使用明确的Executor(例如ThreadPoolExecutor)和您想要的线程数量(很可能远少于1000)来控制使用的线程数量。

    调用不能共享单个线程(调用线程),因为 Java 没有 capability 来解释当今人们对异步的理解,这是由于流行的 async/await 范式(即虚构的“真正异步”术语 - 同步与异步独立于线程,但异步可以通过线程实现,就像在 CompletableFuture 中所做的那样。

    【讨论】:

    • 那么,Java 有没有办法在同一个线程上异步触发多个请求?
    • 参见添加的最后一段。
    【解决方案2】:

    如果您在不指定线程池的情况下安排计算,则将使用 fork-join 公共池,否则您可以指定自己的 ExecutorsupplyAsync 并选择适合您需要的大小。

    【讨论】:

      【解决方案3】:

      尝试使用CompletableFuture.thenCompose() 以异步方式顺序运行多个未来。

      【讨论】: