applyToEither的核心作用是实现两个异步任务的“先到先得”响应模式:谁先完成,就立即用其结果执行指定函数,不等待、不阻塞、不取消另一任务;适用于多源查询、多机房选优、缓存降级等择优响应场景。

applyToEither 的核心作用,就是让两个异步任务“赛跑”,谁先返回结果,就立刻用谁的结果继续往下走——不等、不挑、不阻塞。
它解决的实际问题
很多业务场景天然存在“多路径、择优响应”的需求:
- 调用多个第三方接口查同一类数据(比如天气、物流、价格),只要一个返回就可展示,避免用户长时间等待
- 双机房/多区域服务部署,向两个节点同时发请求,取响应更快的那个,提升首屏速度
- 本地缓存未命中时,同时触发远程加载 + 降级兜底逻辑,谁先成功谁生效
方法签名与关键细节
最常用的是这个重载:
CompletableFuture
- func 只会执行一次,且只作用于最先完成的那个任务的结果
- 另一个仍在运行的任务不会被取消,会继续执行(除非你手动 cancel)
- 如果两个任务都异常完成,最终 CompletableFuture 会以第一个异常为原因完成
- func 在哪个线程执行?默认是“完成得快的那个任务所在线程”,不是主线程,也不是 commonPool 固定线程
async 版本的区别在哪
带 Async 后缀的变体(如 applyToEitherAsync)本质是把 func 的执行“移交”出去:
- 不传 Executor:使用 ForkJoinPool.commonPool(),适合 CPU 密集型处理
- 传自定义 Executor:可指定 IO 线程池,避免阻塞计算线程
- 特别注意:async 不影响两个原始任务本身的执行线程,只影响 func 的执行线程
和 acceptEither 的区别
两者都是“谁快用谁”,但语义不同:
- applyToEither:需要对结果做转换,返回新值(有返回值,类型可变)
- acceptEither:只消费结果,不产出新值(返回 Void,常用于打日志、发通知、更新状态等副作用操作)
选哪个,取决于你下一步是“要结果继续流转”还是“做完就完事”。

















