CompletableFuture acceptEither与acceptEitherAsync区别及线程执行疑问
CompletableFuture的acceptEither与acceptEitherAsync区别及线程执行疑问
一、acceptEither与acceptEitherAsync的核心区别
- 消费逻辑的执行线程:
acceptEither:当任意一个前置Future完成后,消费逻辑(consumer)会直接由完成该Future的线程执行,或者由调用join()/get()等触发Future完成的线程执行,不会额外启用线程池。acceptEitherAsync:消费逻辑会提交到指定线程池(未指定则用ForkJoinPool.commonPool())执行,和完成前置Future的线程完全解耦。
- 异步特性:
acceptEither属于"同步式消费",消费逻辑会占用前置任务的完成线程,可能导致该线程后续任务延迟。acceptEitherAsync是完全异步的消费,消费逻辑在独立线程池中运行,不阻塞前置任务的完成线程。
二、测试代码中stage2线程的疑问解答
你测试代码里的stage2运行在ForkJoinPool.commonPool-worker-5,和acceptEither无关,核心原因是:supplyAsync本身就会把任务提交到ForkJoinPool.commonPool()执行。
代码细节分析
你的测试代码里,两个supplyAsync分别提交了两个独立任务:
import java.util.concurrent.CompletableFuture; public class MyClass { public static void main(String args[]) { System.out.println("hello world, CompletableFuturesRightHere"); CompletableFuture.supplyAsync(() -> { // stage1任务 System.out.println("log-sA: " + Thread.currentThread().getName()); System.out.println("log-sA post: " + Thread.currentThread().getName()); return 40; }).acceptEither(CompletableFuture.supplyAsync(() -> { // stage2任务 System.out.println("log-aE: " + Thread.currentThread().getName()); System.out.println("log-aE post: " + Thread.currentThread().getName()); return 80; }), a -> { System.out.println(a); } ); } }
supplyAsync的无参数重载默认使用ForkJoinPool.commonPool(),所以stage1和stage2会被分配到commonPool的不同worker线程并行执行,这是supplyAsync的行为,和后续的acceptEither无关。- Java文档中提到的"非async方法的依赖操作由完成当前CompletableFuture的线程执行",指的是**
acceptEither绑定的consumer消费逻辑**,而非前置任务的执行线程。你可以修改consumer代码验证:
此时会看到consumer线程是a -> { System.out.println("consumer线程: " + Thread.currentThread().getName() + ", 值: " + a); }worker-3(即完成stage1的线程),完全符合文档描述。
误区澄清
你之前误以为acceptEither控制前置任务的线程,但实际上:
acceptEither仅负责监听两个前置Future的完成状态,哪个先完成就用哪个的线程执行consumer。- 前置Future(stage1、stage2)的执行线程由它们自身的创建方式决定:
supplyAsync默认用commonPool;如果是CompletableFuture.completedFuture()这类同步完成的Future,才会在调用线程执行。
总结
acceptEither和acceptEitherAsync的本质区别是consumer的执行线程来源,前者复用前置任务完成线程,后者使用指定/默认线程池。- 测试代码中stage2运行在worker-5是
supplyAsync的默认行为,和acceptEither无关;acceptEither真正控制的是consumer的执行线程。
内容的提问来源于stack exchange,提问作者samshers
相关产品推荐
相关产品推荐

