Java的CountDownLatch和CyclicBarrier的理解和区别

Java的CountDownLatch和CyclicBarrier的理解和区别CountDownLatch和CyclicBarrier的功能看起来很相似,不易区分,有一种谜之的神秘。本文将通过通俗的例子并结合代码讲解两者的使用方法和区别。CountDownLatch和CyclicBarrier都是java.util.concurrent包下面的多线程工具类。从字面上理解,CountDown表示减法计数,Latch表示门闩的意思,计数为0的时候就可以打开门闩了。Cycli…

大家好,又见面了,我是你们的朋友全栈君。

CountDownLatch和CyclicBarrier的功能看起来很相似,不易区分,有一种谜之的神秘。本文将通过通俗的例子并结合代码讲解两者的使用方法和区别。

CountDownLatch和CyclicBarrier都是java.util.concurrent包下面的多线程工具类。

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

备注:这里我们使用主线程(即main函数)来创建CountDown和CyclicBarrier对象。所以上文将线程分为“主线程”和“其它线程”两类,主要是便于大家理解。需要提醒读者的是,不单单是主线程可以创建该对象,其它当前正在运行的线程也可以创建CountDown和CyclicBarrier对象,此时该current thread扮演了“主线程”的角色。因此,更加准确的方式是将线程分为“当前线程”和“其它线程”,前者表示创建CountDown和CyclicBarrier对象的线程。希望这个备注没有给大家带来更大的困惑。

下面举例说明:

对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。

我们使用代码模拟这个过程,我们模拟了三个玩家,在三个玩家都准备好之后,游戏才能开始。代码的输出结果为:

正在等待所有玩家准备好
player0 已经准备好了, 所使用的时间为 1.235s
player2 已经准备好了, 所使用的时间为 1.279s
player3 已经准备好了, 所使用的时间为 1.358s
player1 已经准备好了, 所使用的时间为 2.583s
开始游戏

CountDownLatch的代码:

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(4);
        for(int i = 0; i < latch.getCount(); i++){
            new Thread(new MyThread(latch), "player"+i).start();
        }
        System.out.println("正在等待所有玩家准备好");
        latch.await();
        System.out.println("开始游戏");
    }

    private static class MyThread implements Runnable{
        private CountDownLatch latch ;

        public MyThread(CountDownLatch latch){
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                Random rand = new Random();
                int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
                Thread.sleep(randomNum);
                System.out.println(Thread.currentThread().getName()+" 已经准备好了, 所使用的时间为 "+((double)randomNum/1000)+"s");
                latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

对于CyclicBarrier,假设有一家公司要全体员工进行团建活动,活动内容为翻越三个障碍物,每一个人翻越障碍物所用的时间是不一样的。但是公司要求所有人在翻越当前障碍物之后再开始翻越下一个障碍物,也就是所有人翻越第一个障碍物之后,才开始翻越第二个,以此类推。类比地,每一个员工都是一个“其他线程”。当所有人都翻越的所有的障碍物之后,程序才结束。而主线程可能早就结束了,这里我们不用管主线程。

我们使用代码来模拟上面的过程。我们设置了三个员工和三个障碍物。可以看到所有的员工翻越了第一个障碍物之后才开始翻越第二个的,下面是运行结果:

main function is finished.
队友1, 通过了第0个障碍物, 使用了 1.432s
队友0, 通过了第0个障碍物, 使用了 1.465s
队友2, 通过了第0个障碍物, 使用了 2.26s
队友1, 通过了第1个障碍物, 使用了 1.542s
队友0, 通过了第1个障碍物, 使用了 2.154s
队友2, 通过了第1个障碍物, 使用了 2.556s
队友1, 通过了第2个障碍物, 使用了 1.426s
队友2, 通过了第2个障碍物, 使用了 2.603s
队友0, 通过了第2个障碍物, 使用了 2.784s

代码:

package com.huai.thread;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3);
        for(int i = 0; i < barrier.getParties(); i++){
            new Thread(new MyRunnable(barrier), "队友"+i).start();
        }
        System.out.println("main function is finished.");
    }


    private static class MyRunnable implements Runnable{
        private CyclicBarrier barrier;

        public MyRunnable(CyclicBarrier barrier){
            this.barrier = barrier;
        }

        @Override
        public void run() {
            for(int i = 0; i < 3; i++) {
                try {
                    Random rand = new Random();
                    int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
                    Thread.sleep(randomNum);
                    System.out.println(Thread.currentThread().getName() + ", 通过了第"+i+"个障碍物, 使用了 "+((double)randomNum/1000)+"s");
                    this.barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

总结:CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是CountDownLatch的下一步的动作实施者是主线程,具有不可重复性;而CyclicBarrier的下一步动作实施者还是“其他线程”本身,具有往复多次实施动作的特点。

为了文章的完整性,补充下面一句话:
** 为了将上面的“通俗理解”进一步拓展,将前文中“主线程”替换成“当前线程”。因为创建和启动CountDownLatch和CyclicBarrier的是不仅仅是main线程,也可以是任意一个线程,这里使用当前线程来代替主线程这样的概念。**。希望这样的描述不会给大家带来额外的困惑。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158413.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python中for循环加速_如何提高python 中for循环的效率[通俗易懂]

    python中for循环加速_如何提高python 中for循环的效率[通俗易懂]对于某个城市的出租车数据,一天就有33210000条记录,如何将每辆车的数据单独拎出来放到一个专属的文件中呢?思路很简单:就是循环33210000条记录,将每辆车的数据搬运到它该去的文件中。但是对于3000多万条数据,一个一个循环太消耗时间,我花了2个小时才搬运了60万数据,算算3000万我需要花费100个小时,也就需要4-5天。并且还需要保证这五天全天开机,不能出现卡机的事故。因此,需要使用并行…

    2022年8月12日
  • MySQL字符与数字转换_MySQL字符与数字间的转换「建议收藏」

    MySQL字符与数字转换_MySQL字符与数字间的转换「建议收藏」MYSQL字符数字转换1.将字符的数字转成数字,比如’0’转成0可以直接用加法来实现例如:将pony表中的d进行排序,可d的定义为varchar,可以这样解决select*fromponyorderby(d+0)2.在进行ifnull处理时,比如ifnull(a/b,’0′)这样就会导致a/b成了字符串,因此需要把’0’改成0,即可解决此困扰。3.比较数字和varchar…

    2022年5月30日
  • 将存储过程执行的结果保存到临时表

    1、创建一个字段名称和数量与存储过程的执行结果一致的临时表;2、insertinto#t1EXECPorc1'a'示例:CREATEPROCEDUREProc1@a

    2021年12月24日
  • SQLPro Studio 激活(在线激活)

    SQLPro Studio 激活(在线激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
  • python少儿趣味编程案例(python少儿编程书)

    Python简单易学,功能强大,是少儿学习编程的首选语言。本书是少儿学习Python编程的趣味指南,全书共17章,按照由简到难、逐步深入的方式组织各章内容。本书从认识Python开始,首先介绍了Python的安装和IDLE的使用,然后依次介绍了变量、数字和字符串、列表、元组和字典、布尔类型等数据类型,以及条件、循环、异常和注释、函数、面向对象编程、文件操作等基础知识,并且通过实际案例讲解了海龟绘图…

    2022年4月10日
  • 微信公众号网页分享功能开发

    微信公众号网页分享功能开发现在每天都可以看到很多微信分享的链接上面有网站或者商家的自定义的分享标题,和分享链接的描述及分享出去的图像,例如下面的分享出去的链接:              上面这个是微信的js-SDK页面分享给微信好友在聊天列表中显示的视觉效果。   微信JS-SDKDemo:这个是微信网页分享出去的标题。   微信JS-SDK,帮助第三方为用户提供更优质的移动web服务:这个…

    2022年6月4日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号