我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

引言

前面一篇文章我们《Java线程并发工具类CountDownLatch原理及用法》它有一个缺点,就是它的计数器只能够使用一次,也就是说当计数器(state)减到为 0的时候,如果 再有线程调用去 await() 方法,该线程会直接通过,不会再起到等待其他线程执行结果起到同步的作用。为了解决这个问题CyclicBarrier就应运而生了。

什么是CyclicBarrier

CyclicBarrier是什么?把它拆开来翻译就是循环(Cycle)和屏障(Barrier

它的主要作用其实和CountDownLanch差不多,都是让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障会被打开,所有被屏障阻塞的线程才会继续执行,不过它是可以循环执行的,这是它与CountDownLanch最大的不同。CountDownLanch是只有当最后一个线程把计数器置为0的时候,其他阻塞的线程才会继续执行。学习CyclicBarrier之前建议先去看看这几篇文章:

《Java高并发编程基础之AQS》

《Java高并发编程基础三大利器之Semaphore》

《Java高并发编程基础三大利器之CountDownLatch》

如何使用

我们首先先来看下关于使用CyclicBarrier的一个demo:比如游戏中有个关卡的时候,每次进入下一关的时候都需要进行加载一些地图、特效背景音乐什么的只有全部加载完了才能够进行游戏:


public class CyclicBarrierExample {
 static class PreTaskThread implements Runnable {
 private String task;
 private CyclicBarrier cyclicBarrier;

 public PreTaskThread(String task, CyclicBarrier cyclicBarrier) {
  this.task = task;
  this.cyclicBarrier = cyclicBarrier;
 }

 @Override
 public void run() {
  for (int i = 0; i < 4; i++) {
  Random random = new Random();
  try {
   Thread.sleep(random.nextInt(1000));
   System.out.println(String.format("关卡 %d 的任务 %s 完成", i, task));
   cyclicBarrier.await();
  } catch (InterruptedException | BrokenBarrierException e) {
   e.printStackTrace();
  }
  }
 }

 public static void main(String[] args) {
  CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
  System.out.println("本关卡所有的前置任务完成,开始游戏... ...");
  });
  new Thread(new PreTaskThread("加载地图数据", cyclicBarrier)).start();
  new Thread(new PreTaskThread("加载人物模型", cyclicBarrier)).start();
  new Thread(new PreTaskThread("加载背景音乐", cyclicBarrier)).start();
 }
 }
}

输出结果如下:

我们可以看到每次游戏开始都会等当前关卡把游戏的人物模型,地图数据、背景音乐加载完成后才会开始进行游戏。并且还是可以循环控制的。

源码分析

结构组成


 
 private final ReentrantLock lock = new ReentrantLock();
 
 private final Condition trip = lock.newCondition();
 
 private final int parties;
 
 private final Runnable barrierCommand;
 
 private Generation generation = new Generation();
  • lock:用于保护屏障入口的锁
  • trip :达到屏障并且不能放行的线程在trip条件变量上等待
  • parties :栅栏开启需要的到达线程总数barrierCommand:最后一个线程到达屏障后执行的回调任务
  • generation:这是一个内部类,通过它实现CyclicBarrier重复利用,每当await达到最大次数的时候,就会重新new 一个,表示进入了下一个轮回。里面只有一个boolean型属性,用来表示当前轮回是否有线程中断。

主要方法

await方法


 public int await() throws InterruptedException, BrokenBarrierException {
 try {
  return dowait(false, 0L);
 } catch (TimeoutException toe) {
  throw new Error(toe); // cannot happen
 }
 }
 
 private int dowait(boolean timed, long nanos)
 throws InterruptedException, BrokenBarrierException,
  TimeoutException {
 final ReentrantLock lock = this.lock;
 lock.lock();
  try {
  //获取barrier当前的 “代”也就是当前循环
  final Generation g = generation;
  if (g.broken)
  throw new BrokenBarrierException();

  if (Thread.interrupted()) {
  breakBarrier();
  throw new InterruptedException();
  }
  // 每来一个线程调用await方法都会进行减1
  int index = --count;
  if (index == 0) { // tripped
  boolean ranAction = false;
  try {
   final Runnable command = barrierCommand;
   // new CyclicBarrier 传入 的barrierCommand, command.run()这个方法是同步的,如果耗时比较多的话,是否执行的时候需要考虑下是否异步来执行。
   if (command != null)
   command.run();
   ranAction = true;
   // 这个方法1. 唤醒所有阻塞的线程,2. 重置下count(count 每来一个线程都会进行减1)和generation,以便于下次循环。
   nextGeneration();
   return 0;
  } finally {
   if (!ranAction)
   breakBarrier();
  }
  }

  // loop until tripped, broken, interrupted, or timed out
  for (;;) {
  try {
   // 进入if条件,说明是不带超时的await
   if (!timed)
    // 当前线程会释放掉lock,然后进入到trip条件队列的尾部,然后挂起自己,等待被唤醒。
   trip.await();
   else if (nanos > 0L)
    //说明当前线程调用await方法时 是指定了 超时时间的!
   nanos = trip.awaitNanos(nanos);
  } catch (InterruptedException ie) {
   //Node节点在 条件队列内 时 收到中断信号时 会抛出中断异常!
   //g == generation 成立,说明当前代并没有变化。
   //! g.broken 当前代如果没有被打破,那么当前线程就去打破,并且抛出异常..
   if (g == generation && ! g.broken) {
   breakBarrier();
   throw ie;
   } else {
   // We're about to finish waiting even if we had not
   // been interrupted, so this interrupt is deemed to
   // "belong" to subsequent execution.
   //执行到else有几种情况?
   //1.代发生了变化,这个时候就不需要抛出中断异常了,因为 代已经更新了,这里唤醒后就走正常逻辑了..只不过设置下 中断标记。
   //2.代没有发生变化,但是代被打破了,此时也不用返回中断异常,执行到下面的时候会抛出 brokenBarrier异常。也记录下中断标记位。
   Thread.currentThread().interrupt();
   }
  }
  //唤醒后,执行到这里,有几种情况?
  //1.正常情况,当前barrier开启了新的一代(trip.signalAll())
  //2.当前Generation被打破,此时也会唤醒所有在trip上挂起的线程
  //3.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
  if (g.broken)
   throw new BrokenBarrierException();
  //唤醒后,执行到这里,有几种情况?
  //1.正常情况,当前barrier开启了新的一代(trip.signalAll())
  //2.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
  if (g != generation)
   return index;
  //唤醒后,执行到这里,有几种情况?
  //.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
  if (timed && nanos <= 0L) {
   breakBarrier();
   throw new TimeoutException();
  }
  }
 } finally {
  lock.unlock();
 }
 }

小结

到了这里我们是不是可以知道为啥CyclicBarrier可以进行循环计数?
CyclicBarrier采用一个内部类Generation来维护当前循环,每一个await方法都会存储当前的generation,获取到相同generation对象的属于同一组,每当count的次数耗尽就会重新new一个Generation并且重新设置count的值为parties,表示进入下一次新的循环。
从这个await方法我们是不是可以知道只要有一个线程被中断了,当代的 generationbroken 就会被设置为true,所以会导致其他的线程也会被抛出BrokenBarrierException。相当于一个失败其他也必须失败,感觉有“强一致性“的味道。

总结

CountDownLanch是为计数器是设置一个值,当多次执行countdown后,计数器减为0的时候所有线程被唤醒,然后CountDownLanch失效,只能够使用一次。

CyclicBarrier是当count0时同样唤醒全部线程,同时会重新设置countparties,重新new一个generation来实现重复利用。

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。感
  • 谢您的阅读,十分欢迎并感谢您的关注。

巨人的肩膀摘苹果

https://javajr.cn/
http://www.360doc.com/content/20/0812/08/55930996_929792021.shtml
https://www.cnblogs.com/xxyyy/p/12958160.html

到此这篇关于阿里一面CyclicBarrier和CountDownLatch的区别是啥的文章就介绍到这了,更多相关CyclicBarrier和CountDownLatch的区别内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

阿里云服务器与数据库的区别一个全面的解析

阿里云服务器与数据库是云服务中两个重要的组成部分。然而,许多人可能并不清楚两者之间的区别。这篇文章将对阿里云服务器和数据库进行详细的解释,帮助读者了解这两者之间的关系和区别。阿里云服务器和数据库的区别阿里云服务器和数据库是两个完全不同的概念。阿里云服务器是一种计算资源,它提供了一个计算环境,可以运行各种应用程序。
阿里云服务器与数据库的区别一个全面的解析
2023-11-19

阿里云服务器的区别一次详细的比较和分析

在选择阿里云服务器时,用户可能会面临一些困惑:不同的服务器类型、配置和价格之间是否存在显著的区别?阿里云服务器之间是否真的存在显著的性能差距?这些问题在本文中将得到解答。阿里云服务器是阿里云提供的一种高性能、可扩展的云计算服务,可以帮助用户快速部署和管理应用程序。阿里云提供了多种类型的服务器,包括通用型服务器、计
阿里云服务器的区别一次详细的比较和分析
2023-11-18

面试必问Linux 命令su和sudo的区别解析

目录1. 准备工作2. su 命令介绍及主要用法2.1 - 参数2.2 切换到指定用户2.3 -c 参数3. sudo 命令介绍及主要用法3.1 主要用法3.2 sudo 工作原理3.3 思考4. 二者的差异对比之前一直对 su 和 sud
2022-07-26

阿里云服务器与虚拟服务器的区别解析

随着互联网的发展,越来越多的企业和个人选择使用云计算服务,其中阿里云服务器和虚拟服务器是两种常见的云计算服务类型。那么,这两种服务有何区别?本文将对阿里云服务器与虚拟服务器的区别进行详细解析。阿里云服务器阿里云服务器是由阿里云提供的云计算服务,用户可以根据需要选择不同的操作系统、配置和实例类型,以实现灵活的资源配
阿里云服务器与虚拟服务器的区别解析
2023-11-02

阿里云轻量应用服务器与ECS的区别解析

阿里云轻量应用服务器和ECS都是阿里云提供的云服务器产品,但是两者在功能、性能和价格等方面有着明显的区别。本文将详细介绍这两款产品的异同点,帮助读者更好地选择和使用云服务器。正文:一、功能区别阿里云轻量应用服务器提供了一系列易于使用的开发工具,例如Web服务器、数据库、缓存等,使得用户可以快速搭建自己的应用。而E
阿里云轻量应用服务器与ECS的区别解析
2023-12-11

阿里云服务器与腾讯数据库的区别一个全面的比较

阿里云服务器和腾讯数据库是两个非常流行的云计算服务,它们在功能、性能、安全性和价格等方面有着显著的区别。本文将对这两个服务进行详细比较,帮助用户选择最适合自己的云计算服务。一、功能阿里云服务器提供了多种操作系统供用户选择,包括Linux、Windows、macOS等,用户可以根据自己的需求选择合适的操作系统。此外
阿里云服务器与腾讯数据库的区别一个全面的比较
2023-11-23

阿里云服务器与云端的区别一个详细的解释

阿里云服务器和云端是两个经常被混淆的术语,它们在很大程度上都指的是云计算服务。但是,它们之间还是存在一些细微的区别的。这篇文章将会对这两个术语进行详细的解释,并揭示它们之间的主要区别。一、阿里云服务器阿里云服务器是阿里云提供的基础计算服务。它是一个物理设备,具有独立的处理器、内存、硬盘等硬件资源。用户可以通过阿里
阿里云服务器与云端的区别一个详细的解释
2023-11-08

阿里云服务器更新周期一次全面的解析

阿里云是全球领先的云计算服务提供商,其服务器性能强大,稳定可靠。然而,很多用户对阿里云服务器的更新周期存在疑问,本文将详细解析阿里云服务器的更新周期,以便用户更好地了解和使用阿里云服务。正文:阿里云服务器的更新周期一般是指服务器的硬件和软件版本更新的时间间隔。阿里云服务器的更新周期主要取决于其服务类型和用户的使用
阿里云服务器更新周期一次全面的解析
2023-10-30

阿里云服务器公网和内网的区别网络布局与安全性解析

本文主要介绍阿里云服务器公网和内网的区别,包括网络布局、安全性和使用场景等方面。旨在帮助读者更好地理解和利用阿里云服务器。正文:阿里云服务器公网和内网是两种不同的网络布局,它们在网络安全性方面有着显著的区别。了解这两者的区别可以帮助用户更好地规划和使用阿里云服务器。首先,阿里云服务器的公网是连接阿里云服务器和外部
阿里云服务器公网和内网的区别网络布局与安全性解析
2023-11-11

阿里云服务器买哪个区的好用?——全面解析

阿里云服务器是阿里云提供的弹性计算服务,它能够满足用户在不同场景下的计算需求。那么,阿里云服务器买哪个区的好用呢?本文将全面解析各个区域的特点,帮助用户做出正确的选择。一、阿里云服务器的区域划分阿里云服务器的区域主要分为华北、华东、华南、西南、中西部、海外等六大区域。每个区域都有自己的特点,选择哪个区域的好用,需
阿里云服务器买哪个区的好用?——全面解析
2023-11-22

阿里云服务器与新网的域名解析服务相同点与区别

本文将详细介绍阿里云服务器与新网的域名解析服务的相同点与区别,以便读者在选择服务器和域名服务时,做出更明智的决策。相同点:都是提供域名解析服务的公司:阿里云和新网都是知名的互联网服务提供商,他们都提供域名解析服务,帮助用户将域名与IP地址关联起来,使用户可以通过域名来访问网站。均支持多种域名后缀:阿里云和新网都支
阿里云服务器与新网的域名解析服务相同点与区别
2023-11-04

腾讯的阿里云服务器性能、价格和优点全面解析

随着互联网的发展,服务器的重要性日益凸显。在众多的服务器品牌中,腾讯和阿里云都是备受瞩目的。那么,腾讯的阿里云服务器怎么样呢?本文将为您详细解析其性能、价格和优点。性能:腾讯的阿里云服务器性能出色。阿里云服务器采用高性能计算芯片,拥有强大的计算能力和存储能力。此外,阿里云服务器还提供了多种计算模式,包括GPU计算
腾讯的阿里云服务器性能、价格和优点全面解析
2023-11-11

阿里云数据库配置详接模块——全面解析阿里云数据库的设置和管理

随着数字化时代的到来,数据库已成为企业信息化建设中的关键组成部分。阿里云数据库作为阿里云推出的一款云数据库服务,凭借其高效稳定、易于管理等优势,深受众多企业用户青睐。本篇文章将详细介绍阿里云数据库的配置详接模块,包括数据库的创建、配置、管理和优化等。一、数据库的创建在阿里云上创建数据库需要通过控制台进行。首先,登
阿里云数据库配置详接模块——全面解析阿里云数据库的设置和管理
2023-10-29

阿里云服务器远程桌面如何解决ip和外网不一样的问

阿里云服务器是目前最常用的云计算服务之一,它提供了各种各样的功能,包括远程桌面访问。然而,有些用户可能会遇到ip和外网不一样的问题,这可能会导致远程桌面访问出现问题。本文将详细说明如何解决这个问题。阿里云服务器远程桌面的ip和外网不一样的问题,通常是由于网络设置的问题导致的。以下是一些可能的解决方案:更改阿里云服
阿里云服务器远程桌面如何解决ip和外网不一样的问
2023-12-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录