zoukankan      html  css  js  c++  java
  • JUC并发工具包之CyclicBarrier & CountDownLatch的异同

    1、介绍

    本文我们将比较一下CyclicBarrierCountDownLatch并了解两者的相似与不同。

    2、两者是什么

    当谈到并发,将这两者概念化的去解释两者是做什么的,这其实是一件很有挑战的事情。

    • 首先,这两者都是管理多线程的工具。
    • 其次,两者都具备让一个或多个线程等待执行的功能。

    2.1、CountDownLatch

    CountDownLatch可以使一个线程阻塞等待其它多个线程执行到countDown方法处,直到最后的count属性递减为0。

    我们可以把这想象成餐馆中待上菜的餐盘(西餐中的餐盘,牛肉,蔬菜,水果,各种点缀),不论厨师在这盘菜中准备多少种食材,服务员都得等到所有的食材都准备好才可以端出去。厨师每准备好一个食材,相当于调用一次countDown()方法。

    2.2、CyclicBarrier

    CyclicBarrier是一个可重复使用对象,当一组线程都在阻塞等待直到所有线程都到达了某一执行点,这时候barrier会置内部属性broken为true表示执行点后面的逻辑可以执行了。

    我们可以把这个理解成一群小伙伴准备去餐馆吃饭,两者约定好了一个时间在哪碰面,两者需等待所有人都到了以后才能一起进入餐馆吃饭。

    2.3、进一步阅读

    想了解这两者各自的细节,可以看下之前写的两篇文章CountDownLatch & CyclicBarrier

    3、任务 vs. 线程

    我们来深入看看这两者语义上的区别。

    正如一开始定义所说的,CyclicBarrier允许多个线程互相等待,然而CountDownLatch允许一个或多个线程去等待多个任务执行完成。

    简而言之,CyclicBarrier管理者一组线程CountDownLatch管理一组任务

    下面的代码中,我们定义了一个count为2的CountDownLatch,接下来我们从单个线程中调用countDown()两次:

    CountDownLatch countDownLatch = new CountDownLatch(2);
    Thread t = new Thread(() -> {
        countDownLatch.countDown();
        countDownLatch.countDown();
    });
    t.start();
    countDownLatch.await();
     
    assertEquals(0, countDownLatch.getCount());
    

    一旦CountDownLatch递减到0,外部的await()方法阻塞结束。

    请注意这种情况下,我们可以让单个线程递减两次,但是CyclicBarrier在这点上却不可以。

    与上面的例子类似,我们又一次创建了parties为2的CyclicBarrier,并在单个线程中调用await()两次:

    CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
    Thread t = new Thread(() -> {
        try {
            cyclicBarrier.await();
            cyclicBarrier.await();    
        } catch (InterruptedException | BrokenBarrierException e) {
            // error handling
        }
    });
    t.start();
     
    assertEquals(1, cyclicBarrier.getNumberWaiting());
    assertFalse(cyclicBarrier.isBroken());
    

    这里可以看到两点区别:

    • 第一点区别就是线程在等待的其实是它自己,也就是barrier本身。
    • 第二点更重要的区别是,第二个await()根本就没有用,单线程不能countDown()两次。

    确实,线程t必须等待其它线程调用await(),从而让内部的count值变为2,线程t的第二次调用await()不会被执行除非barrier的broken值早已为true了。

    在我们的测试中,barrier没有被执行到底是因为我们只创建了一个线程在阻塞,要是有两个线程就会满足barrier被tripped(源码中的术语,表示所有线程都到达执行点)的条件了。,从cyclicBarrier.isBroken()方法返回false来看这一点很明显了。

    4、可重用性

    第二个很明显的区别就是可重用性了,我们来解释一下,当barrier在程序中trip了之后,count值会重置为初始值,也就是parties的值。CountDownLatch和它不同是因为它不会重置属性。

    下面的代码中我们我们定义了count为7的CountDownLatch,让countDown()方法被调用20次:

    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);
    

    我们可以看到即使有20个线程调用countDown()方法,count值一旦到达0之后就不会被重置了。

    和上面的例子类似,我们定义一个parties为7的CyclicBarrier,让它也在20个线程中被调用:

    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);
    

    在这个场景中,我们可以看到线程每调用一次barrier的值都是递减一次,当递减到0的时候就会重置到初始值了。

    5、总结
    总而言之,两者在多线程的同步问题上都是很有用的工具。就两者提供的功能而言,两者从根本上就不一样。当你要把两者应用到你的工作中去的时候要仔细考量一下。

    最后还是一样,代码在这里

  • 相关阅读:
    Xtrabackup的安装
    在 CentOS 7上Virtualbox+phpVirtualBox完整虚拟化环境部署
    用分离、附加的方式实现sql server数据库的备份和还原
    Oracle 11g透明网关连接Sqlserver
    硬盘SMART检测参数详解[转]
    安装了 R2 Integration Servic 之后,SQL Server 2008 Management Studio报错
    jenkins获取git上的源码
    CentOS7配置防火墙
    CentOS 7 安装 Oracle 11.2.0.4
    oralce 11.2.0.4手动创建EM
  • 原文地址:https://www.cnblogs.com/mrcharleshu/p/13154503.html
Copyright © 2011-2022 走看看