三个协调器解决不同问题:Semaphore 限制同时使用资源的任务数,CountDownLatch 等待一组事件完成,CyclicBarrier 让 固定参与者在阶段边界互相等待。选错工具会让计数含义和失败路径难以维护。
Table of contents
Open Table of contents
运行组合实验
下载协调器样例下载, 运行:
java -cp target/classes dev.elaine.concurrency.SynchronizerSample
程序让三个任务通过 Barrier 同时开始,只允许两个任务同时进入受限区,并由 Latch 等待全部完成。输出顺序可以变化, 但必须包含“三项任务同时开始”和“全部完成”。
Semaphore 表示资源许可
new Semaphore(20) 表示最多 20 个并发许可,适合保护数据库连接、外部 API 并发或稀缺设备。获取后必须在 finally
释放:
permits.acquire();
try {
callRemoteService();
} finally {
permits.release();
}
许可数量不是请求速率。20 个许可限制同时进行 20 个调用,不能保证每秒只有 20 个请求。速率限制需要令牌桶等时间模型。
CountDownLatch 表示一次性事件
Latch 初始计数只能递减,达到零后永久开放,不能重置。它适合“等待三个依赖就绪”或“同时启动一批测试”。每个工作任务
都应在 finally 调用 countDown(),否则异常会让等待方永久阻塞。
try {
loadPart();
} finally {
finished.countDown();
}
调用 await(timeout, unit) 并处理返回的 false,不要让请求线程无限等待。
CyclicBarrier 表示重复阶段
Barrier 要求固定数量参与者都调用 await(),最后到达者触发 Barrier Action,然后所有线程进入下一阶段。它可重复使用,
适合分阶段并行计算。
一个参与者被中断、超时或失败会破坏 Barrier,其他等待者收到 BrokenBarrierException。调用方必须把“全组失败”作为协议
处理,而不是只重试单个线程。参与者数量会动态变化时,使用 Phaser 更合适。
选择表
| 需求问题 | 选择 |
|---|---|
| 同时最多 N 个任务访问资源 | Semaphore |
| 一个线程等待 N 个独立事件 | CountDownLatch |
| N 个固定线程每轮互相等待 | CyclicBarrier |
| 参与者动态注册且多阶段 | Phaser |
下一步
阅读并发 Map、List 和 Set 的实现权衡,选择能表达一致性与写入模型的容器。