最简洁可靠的方式是用 CountDownLatch——初始化数量须与子任务数严格一致,每个子任务在初始化成功后调用 countDown()(推荐 try-finally),主线程用带超时的 await() 等待,并配合线程安全容器汇总结果。

主线程等待多个子任务完成初始化,最简洁可靠的方式就是用 CountDownLatch —— 它天然适合“一个线程等多个事件”的场景,无需轮询、不依赖共享变量、线程安全且语义清晰。
初始化 CountDownLatch 的数量必须与子任务数严格一致
这是最关键的一步。latch 的初始计数值代表“待完成的子任务总数”,每完成一个就 countDown(),主线程调用 await() 阻塞直到归零。
- 若数量设少,主线程可能提前唤醒,部分子任务还没初始化完
- 若数量设多,主线程永远阻塞(除非设超时),常见于异常未触发 countDown
- 建议在启动子任务前就确定总数,并作为 final 变量传入各任务或 latch 实例
每个子任务必须在初始化完成后才调用 countDown()
不是在线程启动时,也不是在 run() 开头,而是确保所有初始化逻辑(如连接建立、配置加载、资源预热)真正成功执行完毕后,再执行 latch.countDown()。
- 推荐把
countDown()放在 try-finally 块的 finally 中,防止异常导致漏减 - 如果初始化可能失败,可在 catch 块中记录错误,但仍需 countDown —— 主线程后续可检查各任务状态,而非卡死
- 避免在子任务中重复调用 countDown,否则会破坏计数逻辑
主线程 await 应设置合理超时并处理中断
生产环境不能无限等待。使用带超时的 await(long timeout, TimeUnit unit),并根据初始化预期耗时设定(例如 30 秒)。
- 返回 false 表示超时,此时可主动收集各子任务当前状态、打印未完成列表、触发降级逻辑
- 若 await 被中断(Thread.interrupted()),应恢复中断状态并退出,避免吞掉中断信号
- 不要忽略返回值,超时后继续 proceed 可能引发 NPE 或空指针操作
初始化结果汇总建议通过共享容器 + latch 协同完成
CountDownLatch 只负责“等待完成”,不传递结果。需要汇总数据时,搭配线程安全容器(如 ConcurrentHashMap 或 CopyOnWriteArrayList)即可。
- 主线程初始化一个
Map<String, InitResult>,各子任务初始化成功后 put 自己的结果(key 可为任务名或 ID) - 主线程 await 返回 true 后,遍历该容器获取全部结果,做一致性校验或聚合计算
- 避免用普通 HashMap 或 ArrayList,防止并发写入导致数据丢失或异常

















