基于CyclicBarrier和CountDownLatch的使用区别说明

2018.12.12更新

在学习了CyclicBarrier之后发现,CyclicBarrier也可以实现跟CountDownLatch类似的功能,只需要在它的parties中多设置一个数,将主线程加入等待队列就可以了:

public static void main(String[] args) {
  ExecutorService pool = Executors.newCachedThreadPool();
  int size = 3;
  // 设置参数时,线程实际执行数size+1,将main线程也加到等待队列中
  CyclicBarrier cyclicBarrier = new CyclicBarrier(size + 1);
  for (int i = 0; i < size; i++) {
   int index = i;
   pool.submit(() -> {
    try {
     TimeUnit.SECONDS.sleep(index);
     System.out.println("第" + index + "位运动员准备好了");
     cyclicBarrier.await();
    } catch (Exception e) {
     e.printStackTrace();
    }
   });
  }
  try {
  //主线程也加入等待
   cyclicBarrier.await();
  } catch (Exception e) {
   e.printStackTrace();
  }
  System.out.println(size + "位运动员都准备好了,可以起跑!");
 }

执行结果:

以下是原内容:

我在使用并发线程栅栏的时候发现了两种,分别是CyclicBarrier 和CountDownLatch。对于两者的对比的文章有很多,这里不再赘述。我来说下我的使用过程。

**需求:**有三位运动员,他们一起参加万米赛跑,但是他们准备的时间不同,要等他们都准备好了再开始一起跑。

使用CyclicBarrier 实现:

import java.util.concurrent.*;

public class RunTest {
 public static void main(String[] args) {
  ExecutorService pool = Executors.newCachedThreadPool();
  int size = 3;
  CyclicBarrier cyclicBarrier = new CyclicBarrier(size, () -> {
   System.out.println(size + "位运动员都准备好了,可以起跑!");
   pool.shutdownNow();
  });

  for (int i = 0; i < size; i++) {
   int index = i;
   pool.submit(() -> {
    try {
     TimeUnit.SECONDS.sleep(index);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("第" + index + "位运动员准备好了");
    try {
     cyclicBarrier.await();
    } catch (InterruptedException | BrokenBarrierException e) {
     e.printStackTrace();
    }
   });
  }
 }
}

结果:

可以看到,三位运动员准备的时间分别是1s,2s,3s。系统等到他们都准备好了,再发出起跑的信号。在这里CyclicBarrier 做法是在自己的构造器中new了一个runnable,等待其他线程都执行完,再执行此runnable中的代码。

我们再看看CountDownLatch怎么实现:

import java.util.concurrent.*;

public class RunTest {
 public static void main(String[] args) throws InterruptedException {
  ExecutorService pool = Executors.newCachedThreadPool();
  CountDownLatch countDownLatch = new CountDownLatch(3);
  int size = 3;

  for (int i = 0; i < size; i++) {
   int index = i;
   pool.submit(() -> {
    try {
     TimeUnit.SECONDS.sleep(index);
     countDownLatch.countDown();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("第" + index + "位运动员准备好了");
   });
  }
  countDownLatch.await();
  System.out.println(size + "位运动员都准备好了,可以起跑!");
 }
}

结果同上:

我们可以看到,countDownLatch是采取阻塞主线程的方法实现了线程的统一。他内部有一个计数器,我们在执行完一次线程任务的时候需要手动的减一个数,在主线程中使用 **countDownLatch.await()**监控计数器的状态,知道计数器计到0为止,再执行主线程的代码。

在实际的开发中,我个人比较倾向于第二种方法,因为使用起来简单,完全满足我的需求。

以上这篇基于CyclicBarrier和CountDownLatch的使用区别说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解

    Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 一.CountDownLatch

  • 详解java CountDownLatch和CyclicBarrier在内部实现和场景上的区别

    前言 CountDownLatch和CyclicBarrier两个同为java并发编程的重要工具类,它们在诸多多线程并发或并行场景中得到了广泛的应用.但两者就其内部实现和使用场景而言是各有所侧重的. 内部实现差异 前者更多依赖经典的AQS机制和CAS机制来控制器内部状态的更迭和计数器本身的变化,而后者更多依靠可重入Lock等机制来控制其内部并发安全性和一致性. public class { //Synchronization control For CountDownLatch. //Uses

  • 基于CyclicBarrier和CountDownLatch的使用区别说明

    2018.12.12更新 在学习了CyclicBarrier之后发现,CyclicBarrier也可以实现跟CountDownLatch类似的功能,只需要在它的parties中多设置一个数,将主线程加入等待队列就可以了: public static void main(String[] args) { ExecutorService pool = Executors.newCachedThreadPool(); int size = 3; // 设置参数时,线程实际执行数size+1,将main

  • 解析阿里一面CyclicBarrier和CountDownLatch的区别

    引言 前面一篇文章我们<Java线程并发工具类CountDownLatch原理及用法>它有一个缺点,就是它的计数器只能够使用一次,也就是说当计数器(state)减到为 0的时候,如果 再有线程调用去 await() 方法,该线程会直接通过,不会再起到等待其他线程执行结果起到同步的作用.为了解决这个问题CyclicBarrier就应运而生了. 什么是CyclicBarrier CyclicBarrier是什么?把它拆开来翻译就是循环(Cycle)和屏障(Barrier) 它的主要作用其实和Cou

  • Java中CyclicBarrier和CountDownLatch的用法与区别

    目录 前言 CountDownLatch 例子 CyclicBarrier 构造函数 例子 两者区别 前言 CyclicBarrier和CountDownLatch这两个工具都是在java.util.concurrent包下,并且平时很多场景都会使用到. 本文将会对两者进行分析,记录他们的用法和区别. CountDownLatch CountDownLatch是一个非常实用的多线程控制工具类,称之为"倒计时器",它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行. Coun

  • 基于Python __dict__与dir()的区别详解

    Python下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案. __dict__与dir()的区别: dir()是一个函数,返回的是list: __dict__是一个字典,键为属性名,值为属性值: dir()用来寻找一个对象的所有属性,包括__dict__中的属性,__dict__是dir()的子集: 并不是所有对象都拥有__dict__属性.许多内建类型就没有__dict__属性,如list,此时就需要用dir()来列出对象的所有属性. __di

  • 基于Android MarginLeft与MarginStart的区别(详解)

    我们在写layout布局的时候,我们会发现有这样几个比较相似的属性: MarginStart   MarginLeft MarginEnd    MarginRight 这些属性的区别是什么?  根据api注释,我们得知MarginStart指的是控件距离开头View部分的间距大小,MarginLeft则指的是控件距离左边View部分的间距大小,MarginEnd和MarginRight同理. 一般情况下,View开始部分就是左边,但是有的语言目前为止还是按照从右往左的顺序来书写的,例如阿拉伯语

  • 基于Django OneToOneField和ForeignKey的区别详解

    根据Django官方文档介绍: A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the "reverse" side of the relation will directly return a single object. OneToOneField与ForeignKey加上unique=True效果基本一样,但是用OneToOneField反

  • 基于Python 函数和方法的区别说明

    简单总结: 1.与类和实例无绑定关系的function都属于函数(function): 2.与类和实例有绑定关系的function都属于方法(method). 首先摒弃错误认知:并不是类中的调用都叫方法 函数(FunctionType) 函数是封装了一些独立的功能,可以直接调用,能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值.可以直接在模块中进行定义使用. 所有传递给函数的数据都是显式传递的. 方法(MethodType) 方法和函数类似,同样封装了独立的功能

  • 基于R语言赋值符号的区别说明

    R语言赋值可以用=或<-,一般都建议使用<-,那你知道这两个之间的区间吗?那你有没有见过'<-'和'='这种赋值方法吗?今天就来和大家聊聊这基本的赋值符号都有哪些区别. 首先我们来看看符号的优先级,和java,c这些编程语言的优先级类似.下面这些都取自R帮助文档,输入?Syntax即可查看,它是根据优先级从高到低排列的. :: ::: access variables in a namespace $ @ component / slot extraction [ [[ indexing

  • 基于Python3中运算符 **和*的区别说明

    我们知道**代表次方. 如下 >>>12 * 12 144 >>>12 ** 2 144 >>>a=1e200 >>> a 1e+200 >>>a ** 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> OverflowError: (34, 'Result too large'

  • 基于@MapperScan和@ComponentScan的使用区别

    目录 @MapperScan和@ComponentScan区别 @MapperScan和@ComponentScan使用 原因 解决办法 课外拓展 @MapperScan和@ComponentScan区别 今天在撸SpringBoot的时候,突然对注解产生了混淆,@MapperScan和@ComponentScan都是扫描包,二者之间有什么区别呢? 首先,@ComponentScan是组件扫描注解,用来扫描@Controller @Service @Repository这类,主要就是定义扫描的路

随机推荐