CyclicBarrier & CountDownLatch

CyclicBarrierCountDownLatch 是 Java 并发包(java.util.concurrent)中的两个常用同步工具,它们用于协调多个线程的执行。然而,它们在设计和使用方式上有着显著的区别,特别是在可重复使用方面。

1. CyclicBarrier 是可重复使用的

CyclicBarrier 是一个循环的屏障(cyclic),其主要功能是让一组线程到达某个屏障点后再同时继续执行。当所有线程都到达屏障时,它会自动重置并进入下一轮等待,这就是它“可重复使用”的特性。它的重用性源于每次线程到达屏障后,会自动重置计数器,并允许再次使用。

  • 特点

    • 复用性:一旦所有线程都到达屏障并通过,屏障自动重置,允许这些线程或其他线程再次使用该屏障进行同步。这意味着 CyclicBarrier 可以在多个循环或阶段中重复使用。
    • 栅栏动作CyclicBarrier 还允许在线程到达屏障时执行一个栅栏动作(可选),该动作可以是某个特定的任务,如日志记录、数据汇总等。
  • 示例

    CyclicBarrier barrier = new CyclicBarrier(3); // 3个线程需要到达屏障
    
    Runnable task = () -> {
        try {
            System.out.println(Thread.currentThread().getName() + " 到达屏障");
            barrier.await();  // 等待其他线程到达屏障
            System.out.println(Thread.currentThread().getName() + " 通过屏障");
        } catch (Exception e) {
            e.printStackTrace();
        }
    };
    
    for (int i = 0; i < 3; i++) {
        new Thread(task).start();
    }
    
    // CyclicBarrier 可以重复使用,允许继续同步新的线程到达屏障
    // 运行结果
    Thread-2 到达屏障
    Thread-1 到达屏障
    Thread-0 到达屏障
    Thread-1 通过屏障
    Thread-2 通过屏障
    Thread-0 通过屏障
    

    这里,当所有 3 个线程都到达 barrier.await() 时,屏障将被释放,线程继续执行。在下一轮中,这些线程可以再次使用同一个 CyclicBarrier

2. CountDownLatch 是一次性的

CountDownLatch 是一个倒计时锁存器,它用于让一个或多个线程等待,直到其他线程完成某个操作。当计数器到达 0 时,所有等待的线程被释放,之后 CountDownLatch 就无法再次使用了。

  • 特点

    • 一次性使用CountDownLatch 是一次性的。一旦计数器从初始值倒数到 0,锁存器不能重置,也不能重新计数。如果需要再次使用,只能创建一个新的 CountDownLatch 实例。
    • 没有栅栏动作CountDownLatch 不像 CyclicBarrier 那样有一个统一的屏障动作,它只是一个简单的计数器,控制多个线程的同步。
  • 示例

    CountDownLatch latch = new CountDownLatch(3); // 初始计数为 3
    
    Runnable task = () -> {
        System.out.println(Thread.currentThread().getName() + " 完成任务");
        latch.countDown(); // 每个线程完成任务后调用 countDown()
    };
    
    for (int i = 0; i < 3; i++) {
        new Thread(task).start();
    }
    
    try {
        latch.await();  // 等待计数器变为 0
        System.out.println("所有任务完成,继续执行主线程");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
    // 运行结果:
    Thread-2 完成任务
    Thread-1 完成任务
    Thread-0 完成任务
    所有任务完成,继续执行主线程
    

    在这个例子中,CountDownLatch 初始计数为 3,表示需要 3 个线程完成任务。当计数器变为 0 时,主线程继续执行。然而,CountDownLatch 在计数变为 0 后无法重置,不能再次使用。

3. 为什么 CyclicBarrier 可重复使用,而 CountDownLatch 是一次性的?

  • 设计目的

    • CyclicBarrier:设计的目的是在循环或阶段性任务中使用,它允许同一批线程在不同的阶段都同步等待,完成一轮后可以自动重置并继续下一轮,因此它是循环使用的工具。
    • CountDownLatch:设计目的是让某个线程等待一组操作完成后继续执行,常用于一次性事件(如系统初始化、任务完成的信号)。它的计数一旦减为 0,表示操作已经完成,之后不能重新计数,因此是一次性的工具
  • 实现机制

    • CyclicBarrier:每当线程到达屏障并通过时,屏障自动重置,允许再次使用。其内部维护一个计数器和栅栏代(generation)来实现多次复用。
    • CountDownLatch:计数器一旦减到 0,锁存器就完成任务,无法重置,除非重新创建一个新的实例。

4. 使用场景的差异

  • CyclicBarrier 使用场景

    • 多线程分阶段处理任务时,每个阶段都需要所有线程在某个点上同步。例如,在一个并行算法中,多个线程需要在每个阶段结束时进行同步。
  • CountDownLatch 使用场景

    • 在某些初始化操作中,主线程需要等待其他线程完成后继续执行。例如,一个主线程等待几个工作线程完成任务,然后才继续执行。

总结

  • CyclicBarrier 可重复使用:它的设计允许在多个循环或阶段中重复使用,当一组线程到达屏障后,屏障会自动重置,进入下一轮等待。
  • CountDownLatch 是一次性的:它的计数器一旦到达 0,就无法再次使用,只能用于一次性任务协调。如果需要再次使用,必须创建新的实例。
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

青衫客36

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

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

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

打赏作者

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

抵扣说明:

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

余额充值