CountDownLatch和CyclicBarrier的区别,这回看懂了!

CountDownLatchCyclicBarrier 都是 Java 并发工具包 (java.util.concurrent) 中用于线程协调的类,但它们的用途和行为有本质区别。CountDownLatch是一次性的,等待事件完成;而CyclicBarrier是可循环的,用于线程相互等待。CountDownLatch的计数器由外部控制,而CyclicBarrier由线程自己调用await来减少计数。CountDownLatch适用于主线程等待多个子任务完成,而CyclicBarrier适合分阶段的任务,比如多轮计算。CyclicBarrier有屏障损坏的问题,而CountDownLatch一旦到零就不会改变。CyclicBarrier自动重置,而CountDownLatch需要重新创建。

1. 设计目的

CountDownLatch

  • 单向等待:一个或多个线程等待其他线程完成一组操作。
  • 一次性使用:计数器减到 0 后不可重置。
  • 典型场景:主线程等待所有子任务初始化完成后再继续执行。

CyclicBarrier

  • 多向等待:一组线程互相等待,直到所有线程都到达某个屏障点(Barrier)。
  • 可重复使用:计数器归零后会自动重置(通过 reset() 或自动循环)。
  • 典型场景:多线程分阶段处理任务(如多轮游戏回合)。

2. 参与者数量

CountDownLatch

  • 固定参与者数:在初始化时指定计数器值(new CountDownLatch(N)),后续无法动态调整。
  • 被动等待:其他线程调用 countDown() 减少计数,等待线程调用 await() 阻塞。

CyclicBarrier

  • 动态参与者数:初始化时指定线程数,但可通过 reset() 重新开始(需处理线程中断问题)。
  • 主动同步:所有线程主动调用 await() 等待彼此,直到所有线程到达屏障点。

3. 代码示例

CountDownLatch

// 主线程等待所有子任务完成
CountDownLatch latch = new CountDownLatch(3);

// 子线程完成任务后调用 countDown()
executor.submit(() -> {
    doTask();
    latch.countDown();
});

// 主线程等待所有子任务完成
latch.await();

CyclicBarrier

// 3 个线程互相等待
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    // 所有线程到达屏障后执行的回调(可选)
});

executor.submit(() -> {
    doPhase1();
    barrier.await(); // 等待其他线程
    doPhase2();
});

4. 异常处理

CountDownLatch

  • 如果某个线程未调用 countDown(),主线程可能永远阻塞(需设计超时机制)。

CyclicBarrier

  • 如果某个线程在 await() 时被中断或超时,所有等待线程会抛出 BrokenBarrierException,屏障被标记为“损坏”,需调用 reset() 重置。

5. 适用场景

场景CountDownLatchCyclicBarrier
主线程等待子任务完成✅ 是❌ 否
子线程互相等待❌ 否✅ 是
多次重复同步(多阶段任务)❌ 否✅ 是
动态调整参与者数量❌ 否✅ 是(需手动重置)

总结

  • CountDownLatch一对多 的等待机制,用于外部线程(如主线程)等待其他线程完成任务。
  • CyclicBarrier多对多 的同步机制,用于一组线程互相等待,且支持分阶段任务和重复使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

设计师Linda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值