thenCombine 总是等不到第二个 CompletableFuture 完成,因其不触发执行,只监听两个 future 均已完成;若任一未启动(如未调用 supplyAsync 提交),则永久阻塞。
为什么
总是等不到第二个
完成?
因为
不会主动触发任一入参的执行,它只监听两个
都已完成(
)后才运行合并逻辑。如果你传入一个还没开始执行的
(比如刚用
创建但没被调度),那它永远卡住。
务必确保两个
都已启动:要么调用
/
触发(不推荐),要么确认它们是通过
、
或其他异步方式创建并已提交到线程池
常见错误场景:把同步计算包装成
,另一个却忘了加
后缀,结果后者在当前线程阻塞执行,导致整个链路失去并发性
调试时可加日志:
,验证是否真完成
的函数参数类型必须严格匹配返回值吗?
不是必须“返回值类型相同”,而是两个
的泛型类型(
和
)与 BiFunction 的输入类型一一对应,输出类型决定整个
调用的返回类型。
写法必须是:
,其中
是
的结果类型,
是
的结果类型
如果
是
,
是
,BiFunction 就得声明为
,返回
容易踩坑:误把
的结果当成
类型去强转,抛
;或者 BiFunction 返回
导致下游
收到 null 而 NPE
多个
嵌套时线程切换混乱,怎么稳住执行上下文?
默认使用
,每次调用都可能换线程;嵌套越深,越难预测哪个线程在跑哪段逻辑,尤其涉及 ThreadLocal 或数据库连接时极易出错。
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
显式指定执行器是最稳妥的做法:
如果两个源 future 都来自同一自定义线程池(如
),它们的
回调默认仍走 commonPool —— 必须用
才能延续上下文
性能提示:频繁跨线程切换 + 小任务 = 调度开销压倒计算收益;若合并逻辑极轻量(如字符串拼接),可考虑用
(无 Async 后缀),靠 commonPool 批量处理更高效
异常传播被吞掉?
对失败的 future 怎么反应?
只要任意一个入参 future 以异常结束,
返回的新 future 就会直接进入异常状态,**不会调用你传的 BiFunction**,也不会静默失败 —— 但很多人没接
或
,导致异常“消失”。
立即学习
“
Java免费学习笔记(深入)
”;
典型现象:控制台没报错,但后续
死活不执行 → 先检查上游是否有未处理的异常
正确做法:在
后立刻链式加
注意:如果想区分是哪个 future 失败,不能只靠
;得提前用
分别包裹两个源 future,把异常转成特定标记值(如
),再在 BiFunction 里判断
实际编排中,最常被忽略的是「两个 future 的生命周期是否真正解耦」——比如共用同一个缓存对象或静态计数器,表面并发,实则串行竞争。这时候看日志时间戳比看代码更容易发现问题。
thenCombineCompletableFuturethenCombineCompletableFutureisDone() == trueCompletableFuturesupplyAsyncCompletableFuturejoin()get()supplyAsyncrunAsynccompletedFuture(x)asyncfuture1.whenComplete((v, t) -> System.out.println("f1 done"))thenCombineCompletableFutureTUthenCombinecf1.thenCombine(cf2, (t, u) -> {...})tcf1ucf2cf1CompletableFuturecf2CompletableFuture(String, Integer) -> BooleanCompletableFuturecf2cf1ClassCastExceptionnullthenApplythenCombinethenCombineForkJoinPool.commonPool()cf1.thenCombine(cf2, (a,b) -> f(a,b)).thenApplyAsync(x -> g(x), myExecutor)Executors.newFixedThreadPool(4)thenCombinethenCombineAsync(..., executor)thenCombinethenCombinethenCombineexceptionallyhandlethenAcceptthenCombineexceptionally(e -> { log.error("", e); return fallbackValue; })thenCombinehandleOptional.empty()