CountDownLatch和CyclicBarrier的区别

本文详细解析了CountDownLatch和CyclicBarrier两种线程控制工具的区别,包括它们的使用场景、工作原理以及如何在代码中实现。CountDownLatch用于主线程等待其他线程完成任务,而CyclicBarrier则允许一组线程相互等待,直至到达某个公共屏障点。

CountDownLatch和CyclicBarrier的区别

  从字面上理解,CountDown表示减法计数,Latch表示门闩的意思,计数为0的时候就可以打开门闩了Cyclic Barrier表示循环的障碍物。两个类都含有这一个意思:对应的线程都完成工作之后再进行下一步动作,也就是大家都准备好之后再进行下一步。然而两者最大的区别是,进行下一步动作的动作实施者是不一样的。这里的“动作实施者”有两种,一种是主线程(即执行main函数),另一种是执行任务的其他线程,后面叫这种线程为“其他线程”,区分于主线程。对于CountDownLatch,当计数为0的时候,下一步的动作实施者是main函数;对于CyclicBarrier,下一步动作实施者是“其他线程。CountDownLatch是一次性的,而 CyclicBarrie可以继续使用。

  总结

CountDownLatch:使用state进行计数,不断递减,计数为0的时候,下一步的动作实施者是main函数。CountDownLatch是一次性的
CyclicBarrier:使用parties进行计数,不断递增,计算最大时,下一步动作实施者是“其他线程。CyclicBarrie可以继续使用。

场景举例说明

  CountDownLatch:我们模拟了三个玩家,在三个玩家都准备好之后,游戏才能开始。运行结果:

正在等待所有玩家准备好

Thread-0 已经准备好了

Thread-1 已经准备好了

Thread-2 已经准备好了

开始游戏

public class MyCountDownLatch {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for(int i = 0; i<countDownLatch.getCount();i++) {
            Thread thread = new Thread(new Thread1(countDownLatch));
            thread.start();
        }
        try {
            System.out.println("正在等待所有玩家准备好");
            countDownLatch.await();
            System.out.println("开始游戏");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class Thread1 implements Runnable{
        private CountDownLatch countDownLatch;
        public Thread1(CountDownLatch countDownLatch){
            this.countDownLatch = countDownLatch;
        }
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+" 已经准备好了");
                countDownLatch.countDown();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

}

  CyclicBarrier:我们模拟三个员工和三个障碍物。可以看到所有的员工翻越了第一个障碍物之后才开始翻越第二个的,下面是运行结果:

ok

Thread-1, 通过了第0个障碍物

Thread-0, 通过了第0个障碍物

Thread-2, 通过了第0个障碍物

Thread-2, 通过了第1个障碍物

Thread-1, 通过了第1个障碍物

Thread-0, 通过了第1个障碍物

Thread-0, 通过了第2个障碍物

Thread-2, 通过了第2个障碍物

Thread-1, 通过了第2个障碍物

public class MyCyclicBarrier {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        for (int i = 0; i<cyclicBarrier.getParties(); i++) {
            Thread thread = new Thread(new Thread1(cyclicBarrier));
            thread.start();
        }
        System.out.println("ok");
    }

    static class Thread1 implements Runnable{
        private CyclicBarrier cyclicBarrier;
        public Thread1(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            for(int i = 0; i < 3; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ", 通过了第"+i+"个障碍物");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
`CountDownLatch` `CyclicBarrier` 是 Java 中用于控制线程同步的两个工具类,它们都位于 `java.util.concurrent` 包中,但它们的用途行为有显著区别: ### 1. **用途不同** - **CountDownLatch** 适用于一个或多个线程等待其他线程完成一系列操作后才能继续执行的场景。它通过一个计数器来控制线程的等待,计数器初始化为一个正整数,每次调用 `countDown()` 方法会减少计数器的值,当计数器变为 0 时,所有等待的线程被释放。 - **CyclicBarrier** 适用于多个线程相互等待,直到所有线程都到达一个屏障点后再一起继续执行。它允许一组线程互相等待,直到所有线程都到达某个公共屏障点。 ### 2. **是否可重用** - **CountDownLatch** 不可重用,计数器一旦减到 0,就不能再被重置。 - **CyclicBarrier** 可以重复使用,当所有线程到达屏障点后,计数器会被重置为初始值,可以再次使用。 ### 3. **线程阻塞方式** - **CountDownLatch** 线程通过调用 `await()` 方法等待计数器变为 0,而其他线程通过调用 `countDown()` 来减少计数器。 - **CyclicBarrier** 每个线程调用 `await()` 后会进入等待状态,直到所有线程都调用 `await()`,此时屏障被解除,所有线程继续执行。 ### 4. **异常处理** - **CountDownLatch** 如果某个等待线程被中断,不会影响其他线程的计数。 - **CyclicBarrier** 如果某个线程在等待时被中断或超时,会触发 `BrokenBarrierException`,并且屏障会被打破,其他线程也会收到异常。 ### 示例代码 #### CountDownLatch 示例 ```java import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); for (int i = 1; i <= 3; i++) { final int threadId = i; new Thread(() -> { System.out.println("Thread " + threadId + " is working..."); latch.countDown(); // 完成任务后计数减一 }).start(); } latch.await(); // 主线程等待所有子线程完成 System.out.println("All threads have finished their work."); } } ``` #### CyclicBarrier 示例 ```java import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierExample { public static void main(String[] args) { CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All threads have reached the barrier."); }); for (int i = 1; i <= 3; i++) { final int threadId = i; new Thread(() -> { try { System.out.println("Thread " + threadId + " is working..."); barrier.await(); // 等待所有线程到达屏障 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } } ``` ### 总结 - `CountDownLatch` 是 **一次性** 的,适合一个线程等待多个任务完成。 - `CyclicBarrier` 是 **可重复使用** 的,适合多个线程相互等待,直到所有线程都到达某个屏障点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值