当前位置: 首页 > article >正文

学技术学英文:java CyclicBarrier 和 CountDownLatch用法区别,举例生动看完不会忘

导读:

1. CyclicBarrier 和 CountDownLatch 都是java中让线程阻塞等待的,CountDownLatch是父线程等待,CyclicBarrier是子线程等待。

2. CountDownLatch 使用典型场景:主线程依次启动了线程A、线程B , 现在主线程需要等待线程AB全部执行完后,再执行主线程后续代码,那么就需要阻塞等待主线程了。 new CountDownLatch(2) 设置一个阈值(这里是2,因为需要等待AB两个线程),A执行完减1, B执行完减1 ,当阈值减为0后,主线成继续执行后面代码。

3. 一个线程可以CountDownLatch.countDown() 多次,初始化CountDownLatch时候可以设置比实际线程数多的值,与countDown()次数一致即可。

4. CyclicBarrier 文中举了请客吃饭的例子,客人(子线程)全部到齐了,每个客人才能动筷子(子线程阻塞终止)

5.  CyclicBarrier.await() 调用一次当前线程就会阻塞,最后一个线程CyclicBarrier.await()后,所有线程被唤醒,一次阻塞结束。  第一个线程调用CyclicBarrier.await() 返回size-1, 最后一个调用await()  返回0然后一轮结束, 如果某个线程后续第二次调用await()那么开启下一轮等待(吃下顿饭了), 源码如下,注意nextGeneration()的逻辑,count还原,如果只有一个线程错误调用了await()两次,那么第二轮该线程就永远卡死了。

6. 参考上一条原因,所以 CyclicBarrier 是可以重复用的,一轮又一轮,这就是Cyclic这个单词的本源。CountDownLatch只能用一次,countDown到0 就不能再用了。

1. Introduction

In this tutorial, we’ll compare CyclicBarrier and CountDownLatch and try to understand the similarities and differences between the two.

2. What Are These?

When it comes to concurrency, it can be challenging to conceptualize what each is intended to accomplish.

First and foremost, both CountDownLatch and CyclicBarrier are used for managing multi-threaded applications.

And, they are both intended to express how a given thread or group of threads should wait.

2.1. CountDownLatch

CountDownLatch is a construct that a thread waits on while other threads count down on the latch until it reaches zero.

We can think of this like a dish at a restaurant that is being prepared. No matter which cook prepares however many of the items, the waiter must wait until all the items are on the plate. If a plate takes items, any cook will count down on the latch for each item she puts on the plate.

2.2. CyclicBarrier

CyclicBarrier is a reusable construct where a group of threads waits together until all of the threads arrive. At that point, the barrier is broken and an action can optionally be taken.

We can think of this like a group of friends. Every time they plan to eat at a restaurant they decide a common point where they can meet. They wait for each other there, and only when everyone arrives can they go to the restaurant to eat together.

2.3. Further Reading

And for a lot more detail on each of these individually, refer to our previous tutorials on CountDownLatch and CyclicBarrier respectively.

3. Tasks vs. Threads

Let’s take a deeper dive into some of the semantic differences between these two classes.

As stated in the definitions, CyclicBarrier allows a number of threads to wait on each other, whereas CountDownLatch allows one or more threads to wait for a number of tasks to complete.

In short, CyclicBarrier maintains a count of threads whereas CountDownLatch maintains a count of tasks.

In the following code, we define a CountDownLatch with a count of two. Next, we call countDown() twice from a single thread:

CountDownLatch countDownLatch = new CountDownLatch(2);

Thread t1 = new Thread(() -> {
    System.out.println("t1我的任务完了!");

    countDownLatch.countDown();

});

t1.start();


Thread t2 = new Thread(() -> {
    System.out.println("t2我的任务完了!");

    countDownLatch.countDown();

});

t2.start();


countDownLatch.await();

Once the latch reaches zero, the call to await returns.

Note that in this case, we were able to have the same thread decrease the count twice.

CyclicBarrier, though, is different on this point.

Similar to the above example, we create a CyclicBarrier, again with a count of two and call await() on it, this time from the same thread:

CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

Thread t1 = new Thread(() -> {
    try {

        cyclicBarrier.await();
        System.out.println("t1人到齐了,我开始吃了");

    } catch (InterruptedException | BrokenBarrierException e) {
        // error handling
    }

});

t1.start();


Thread t2 = new Thread(() -> {
    try {

        cyclicBarrier.await();
        System.out.println("t2人到齐了,我开始吃了");

    } catch (InterruptedException | BrokenBarrierException e) {
        // error handling
    }

});

t2.start();

The first difference here is that the threads that are waiting are themselves the barrier.

Second, and more importantly, the second await() is useless. A single thread can’t count down a barrier twice.

Indeed, because t must wait for another thread to call await() – to bring the count to two – t‘s second call to await() won’t actually be invoked until the barrier is already broken!

In our test, the barrier hasn’t been crossed because we only have one thread waiting and not the two threads that would be required for the barrier to be tripped. This is also evident from the cyclicBarrier.isBroken() method, which returns false.

4. Reusability

The second most evident difference between these two classes is reusability. To elaborate, when the barrier trips in CyclicBarrier, the count resets to its original value. CountDownLatch is different because the count never resets.

In the given code, we define a CountDownLatch with count 7 and count it through 20 different calls:

CountDownLatch countDownLatch = new CountDownLatch(7);ExecutorService es = Executors.newFixedThreadPool(20);for (int i = 0; i < 20; i++) {

    es.execute(() -> {

        long prevValue = countDownLatch.getCount();

        countDownLatch.countDown();

        if (countDownLatch.getCount() != prevValue) {

            outputScraper.add("Count Updated");

        }

    });

}

es.shutdown();



assertTrue(outputScraper.size() <= 7);

We observe that even though 20 different threads call countDown(), the count doesn’t reset once it reaches zero.

Similar to the above example, we define a CyclicBarrier with count 7 and wait on it from 20 different threads:

CyclicBarrier cyclicBarrier = new CyclicBarrier(7);

ExecutorService es = Executors.newFixedThreadPool(20);for (int i = 0; i < 20; i++) {

    es.execute(() -> {

        try {

            if (cyclicBarrier.getNumberWaiting() <= 0) {

                outputScraper.add("Count Updated");

            }

            cyclicBarrier.await();

        } catch (InterruptedException | BrokenBarrierException e) {

            // error handling

        }

    });

}

es.shutdown();



assertTrue(outputScraper.size() > 7);

In this case, we observe that the value decreases every time a new thread runs, by resetting to the original value, once it reaches zero.

5. Conclusion

All in all, CyclicBarrier and CountDownLatch are both helpful tools for synchronization between multiple threads. However, they are fundamentally different in terms of the functionality they provide. Consider each carefully when determining which is right for the job.


http://www.kler.cn/a/448325.html

相关文章:

  • aws(学习笔记第十九课) 使用ECS和Fargate进行容器开发
  • 边缘智能网关助力打造建筑智慧消防物联网
  • UVM 验证方法学之interface学习系列文章(十二)virtual interface 终结篇
  • 2.4 网络概念(分层、TCP)
  • C++ OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制)
  • 日本充电桩标准--CHAdeMO介绍
  • Unity中通过代码设置材质HDR颜色的方法参考
  • opencv 项目--图像匹配
  • (13)CT137A- 简易音乐盒设计
  • sentinel学习笔记4-SPI 在 Sentinel 中的应用
  • 本地电脑生成SSH公钥私钥对,用于SSH远程连接服务器
  • 【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
  • 泛型(2)
  • 开源!自制一个桌面宠物(STM32CUBEMX HAL库 PWM波 小项目)
  • 在 CUDA C/C++ 中使用共享內存
  • 路径规划之启发式算法之二十一:禁忌搜索算法(Tabu Search,TS)
  • Linux 端口操作
  • 【游戏设计原理】21 - 解谜游戏的设计
  • 【Mac】安装 PaddleOCR
  • springboot java ffmpeg 视频压缩、提取视频帧图片、获取视频分辨率
  • IntelliJ IDEA Docker集成
  • 适用于.net的操作excel的库
  • vsCode怎么使用vue指令快捷生成代码
  • stm32实现出厂设置和恢复出厂设置
  • python --机器学习(KNN相关)
  • 算法之物品移动