官网解释:

  • 允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。

意思就是每个线程都得执行到等待点进行等待,直到所有线程都执行到等待点,才会继续往下执行。相当于日常开会,只有等每个参会的人都到之后才会开始会议。

用法:(以开会举例)

1、会议需要三个人
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {@Overridepublic void run()2、这是三个人都到齐之后会执行的代码System.out.println("三个人都已到达会议室")}});3、定义三个线程,相当于三个参会的人for (int i = 0; i < 3; i++) {final int finalI = i;new Thread(new Runnable() {@Overridepublic void run() {try {4、模拟每人到会议室所需时间 Thread.sleep((long) (Math.random()*5000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("第"+Thread.currentThread().getName()+"个人到达会议室");try {5、等待其他人到会议室 cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"开始开会");}}, String.valueOf(finalI)).start();}

上述代码运行的结果为:

源码解析:

一、构造方法

有两个构造方法,只有带Runnable参数的构造方法才会在所有线程都到达等待点之后执行Runnable里面的run方法。

CyclicBarrier(int parties) {this(parties, null);
}CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();this.parties = parties;this.count = parties;this.barrierCommand = barrierAction;
}

二、维护锁状态逻辑

其底层使用ReentrantLock+Condition进行锁状态的维护

1、维护锁状态
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
2、线程组数
private final int parties;
3、所有线程到达等待点后执行的Runnable
private final Runnable barrierCommand;
4、需要等待的线程数量
private int count;
6、屏障点定义
private static class Generation {boolean broken = false;
}

具体看看其是如何实现等待逻辑的,线程等待需要调用await方法

public int await() {return dowait(false, 0L);}public int await(long timeout, TimeUnit unit){return dowait(true, unit.toNanos(timeout));
}

最终调用的是dowait方法

private int dowait(boolean timed, long nanos){final ReentrantLock lock = this.lock;1、获取锁lock.lock();try {final Generation g = generation;if (g.broken)throw new BrokenBarrierException();2、如果线程中断,重置等待线程数量并且唤醒当前等待的线程 if (Thread.interrupted()) {breakBarrier();throw new InterruptedException();}3、等待线程数减1int index = --count;4、当等待线程数为 时if (index == 0) {  // trippedboolean ranAction = false;try {5、执行所有线程都到达等待点之后的Runnable final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;6、唤醒所有线程并生成下一代 nextGeneration();return 0;} finally {if (!ranAction)breakBarrier();}}7、如果等待线程数不为0for (;;) {try {8、根据传入的参数来决定是定时等待还是非定时等待if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {9、线程中断之后唤醒所有线程并进入下一代if (g == generation && ! g.broken) {breakBarrier();throw ie;} else { Thread.currentThread().interrupt();}}10、如果线程因为打翻屏障操作而被唤醒则抛出异常if (g.broken)throw new BrokenBarrierException();11、如果线程因为换代操作而被唤醒则返回计数器的值if (g != generation)return index;12、如果线程因为时间到了而被唤醒则打翻栅栏并抛出异常if (timed && nanos <= 0L) {breakBarrier();throw new TimeoutException();}}} finally {lock.unlock();}}

可以看到,是通过index字段控制线程等待的,当index不为0的时候,线程统一会进行阻塞,直到index为0的时候,才会唤醒所有线程,这时候所有线程才会继续往下执行。

三、重复使用

这个跟CountdownLatch不一样的是,CountdownLatch是一次性的,而CycliBarrier是可以重复使用的,只需调用一下reset方法。

public void reset() {final ReentrantLock lock = this.lock;lock.lock();try {1、破坏当前的屏障点并唤醒所有线程 breakBarrier();   2、生成下一代nextGeneration(); } finally {lock.unlock();}
}private void breakBarrier() {generation.broken = true;将等待线程数量重置count = parties;唤醒所有线程 trip.signalAll();
}private void nextGeneration() {唤醒所有线程trip.signalAll();将等待线程数量重置count = parties;generation = new Generation();
}

上述就是对CycliBarrier的解析。

CyclicBarrier底层实现和原理相关推荐

  1. go底层系列-defer原理剖析

    go底层系列-defer原理剖析 目录 go底层系列-defer原理剖析 defer 前言 热身 defer规则 规则一:延迟函数的**参数在defer语句出现时就已经确定下来**了 规则二:延迟函数 ...

  2. currenthashmap底层的CAS原理

    currenthashmap底层的CAS原理 介绍CAS CAS的全称是Compare And Swap 即比较交换,其算法核心思想如下 如果V值等于E值,则将V的值设为N.若V值和E值不同,则说明已 ...

  3. JUC多线程:CountDownLatch、CyclicBarrier、Semaphore同步器原理总结

    一.CountDownLatch: 1.什么是 CountDownLatch: CountDownLatch,闭锁,就是一个基于 AQS 共享模式的同步计数器,它内部的方法都是围绕 AQS 实现的.主 ...

  4. .NET Micro Framework动态调用C/C++底层代码(原理篇)

    .NET Micro Framework和WinCE系统不同,从应用开发角度来说,仅支持C#开发(从V4.2版本开始,才支持VB.NET开发),而不像WinCE应用开发,既可以用C#/VB.Net,也 ...

  5. Java集合,ConcurrentHashMap底层实现和原理(常用于并发编程)

    为什么80%的码农都做不了架构师?>>>    概述 ConcurrentHashMap常用于并发编程,这里就从源码上来分析一下ConcurrentHashMap数据结构和底层原理. ...

  6. 阿里P8架构师谈:深入探讨HashMap的底层结构、原理、扩容机制

    摘要 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型. 随着JDK(Java Developmet Kit)版本的更新,JDK1.8对HashMap底层的实现进行了优化, ...

  7. HashMap底层实现及原理

    注意:文章的内容基于JDK1.7进行分析.1.8做的改动文章末尾进行讲解.       一.先来熟悉一下我们常用的HashMap: 1.HashSet和HashMap概述 对于HashSst及其子类而 ...

  8. 【Java基础】HashMap底层数据结构及其原理

    1.简单了解一下HashMap HashMap 就是以 Key-Value 键值对的方式进行数据存储的一种数据结构,它在 JDK 1.7 和 JDK 1.8 中底层数据结构是有些不一样的.简单来说,J ...

  9. 微信小程序底层框架实现原理

    小册介绍 小程序(Mini Program)我们都很熟悉,它是一种不用下载安装就能使用的应用,它实现了应用"触手可及"的梦想.如今,微信已经把小程序打造成了新的开发者生态,而小程序 ...

最新文章

  1. .NET2.0抓取网页全部链接【月儿原创】
  2. Can't call rollback when autocommit=true
  3. 360下载的mysql_MySQL数据库5.7
  4. python集合应用场景_十、python 集合的定义与使用
  5. 前端学习(1928)vue之电商管理系统电商系统之美化一层循环的UI结构for循环ui美化
  6. Linux bunzip2命令:bz2格式的解压缩命令
  7. 安卓应用安全指南 4.2.1 创建/使用广播接收器 示例代码
  8. mysql 绑定 cpu 节点_MySQL Cluster(MySQL集群)配置
  9. 聊聊你们关心的视频号
  10. LINUX安装C#开发环境
  11. NClay框架AOP功能简介
  12. 朗格Lange 1古董车展特别版表落谁家?法拉利 335 Sport非常合衬
  13. Linux下使用php实现office转PDF
  14. 微商史上最全软文标题写作套路(收藏版)
  15. argis加载tpk离线包
  16. 阿里 P10 是怎样的存在?
  17. java静态网页_【屌炸天源码分享】《企业网站html静态网页模板》
  18. 苹果收取30%过路费_你是顶是踩?
  19. WPF编程,使用字体图标的一种方法。
  20. [Unity3D]用C#在unity里面写一个简单的红绿灯

热门文章

  1. Python之快速排序算法实现(二)
  2. Leetcode每日一题:20.valid-parentheses(有效的括号)
  3. Java虚拟机(四)——类加载机制
  4. 机器学习-吴恩达-笔记-12-推荐系统
  5. JS基础入门篇(四)—this的使用,模拟单选框,选项卡和复选框
  6. 第十五:Pytest-html报告修改与汉化
  7. vba 保存word里面的图片_笔记7 【office精华课】一套课程学会Word+Excel+PPT(一)【Word】(2020年第37周 周五)...
  8. java 关闭阻塞线程池_如果优雅地关闭ExecutorService提供的java线程池
  9. Linux根据启动程序文件名称进行批量结束任务
  10. [Spring Boot核心功能]1. SpringApplication 启动引导类(2)