CyclicBarrier,一个同步辅助类,在API中是这么介绍的:

它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

通俗点讲就是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

先可以看下测试结果:

等待线程进来之后并没有立即去执行相关业务逻辑,当线程达到你设计的要求之后才回去执行相关业务逻辑数据,测试代码如下

package com.cxy.cyclicBarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by Administrator on 2017/4/10.
*/
public class CyclicBarrierDemo {
private static CyclicBarrier cyclicBarrier=new CyclicBarrier(); public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i =;i< ;i++){
System.out.println("创建线程"+i);
final int threadNum =i;
Thread.sleep();
executorService.execute( ()->{
try {
cxyDemo(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); }
private static void cxyDemo(int threadNum) throws InterruptedException, BrokenBarrierException {
Thread.sleep();
System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
cyclicBarrier.await();
System.out.println(threadNum); }
}

其中利用到lamba表达式,

利用到可缓存的线程池,可以其中有个注释不是很对

  public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= ) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
} /**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties) {
this(parties, null);
}

两个构造方法:

第一个需要传入线程数,还有就是Runnable

第二个 需要传入得线程数

这个参数定义的线程数,当线程数到设置的值,那么就回去执行awit方法后面的逻辑

在我上面案例中使用的是第一种构造方法:

下面将使用第二种案例:

package com.cxy.cyclicBarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by Administrator on 2017/4/10.
*/
public class CyclicBarrierDemo {
/* private static CyclicBarrier cyclicBarrier=new CyclicBarrier(10); public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i =0;i< 10;i++){
System.out.println("创建线程"+i);
final int threadNum =i;
Thread.sleep(1000);
executorService.execute( ()->{
try {
cxyDemo(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); }
private static void cxyDemo(int threadNum) throws InterruptedException, BrokenBarrierException {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
cyclicBarrier.await();
System.out.println(threadNum); }*/
private static CyclicBarrier cyclicBarrier; static class CyclicBarrierThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName() + "到了"); //等待
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
cyclicBarrier = new CyclicBarrier(, new Runnable() {
@Override
public void run() {
System.out.println("人到齐了,开始吧....");
}
});
for (int i = ; i < ; i++) {
new CyclicBarrierThread().start();
}
}
}

执行结果:

那么await方法到底干了什么呢:

   public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}

最终调用的dowait方法: /**

     * Main barrier code, covering the various policies.
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {       //实现锁,安全
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
        //分代被破坏,异常抛出
if (g.broken)
throw new BrokenBarrierException(); if (Thread.interrupted()) {
          //线程被中断,
breakBarrier();
throw new InterruptedException();
}
        //线程进来,减少数据量
int index = --count;
if (index == ) { // tripped
          // 达到指定的数量时候,执行
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
            //唤醒线程
ranAction = true;
            //更新分代
nextGeneration();
return ;
} finally {
if (!ranAction)
breakBarrier();
}
} // loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
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.
Thread.currentThread().interrupt();
}
} if (g.broken)
throw new BrokenBarrierException(); if (g != generation)
return index; if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
        //最终释放锁
lock.unlock();
}
}
  • 最后一个线程到达,即index == 0
  • 超出了指定时间(超时等待)
  • 其他的某个线程中断当前线程
  • 其他的某个线程中断另一个等待的线程
  • 其他的某个线程在等待barrier超时
  • 其他的某个线程在此barrier调用reset()方法。reset()方法用于将屏障重置为初始状态

应用场景;开会,还有就是例如现金很火的游戏,只有等待大家准备好了,才开始执行进入房间

JUC包下CyclicBarrier学习笔记的更多相关文章

  1. JUC包下Semaphore学习笔记

    在Java的并发包中,Semaphore类表示信号量.Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理.Semaphore有两个构造函数,参数 ...

  2. JUC包下CountDownLatch学习笔记

    CountDownLatch的作用是能使用多个线程进来之后,且线程任务执行完毕之后,才执行, 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于 ...

  3. Linux下iptables学习笔记

    Linux下iptables学习笔记 在Centos7版本之后,防火墙应用已经由从前的iptables转变为firewall这款应用了.但是,当今绝大多数的Linux版本(特别是企业中)还是使用的6. ...

  4. YOLO---Darknet下的学习笔记 V190319

    YOLO---Darknet下的学习笔记 @WP 20190319 很久没有用YOlO算法了,今天又拿过来玩玩.折腾半天,才好运行通的,随手记一下: 一是,终端下的使用.二是,python接口的使用. ...

  5. YOLO---Darknet下的学习笔记

    YOLO.V3-Darknet下的学习笔记 @wp20180927 [目录] 一. 安装Darknet(仅CPU下) 2 1.1在CPU下安装Darknet方式 2 1.2在GPU下安装Darknet ...

  6. JUC.Lock(锁机制)学习笔记[附详细源码解析]

    锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...

  7. 20135202闫佳歆--week5 系统调用(下)--学习笔记

    此为个人笔记存档 week 5 系统调用(下) 一.给MenuOS增加time和time-asm命令 这里老师示范的时候是已经做好的了: rm menu -rf 强制删除 git clone http ...

  8. juc包:使用 juc 包下的显式 Lock 实现线程间通信

    一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...

  9. 【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore

    前言 JUC中为了满足在并发编程中不同的需求,提供了几个工具类供我们使用,分别是CountDownLatch.CyclicBarrier和Semaphore,其原理都是使用了AQS来实现,下面分别进行 ...

随机推荐

  1. Idea的基本介绍

    Idea的基本介绍 Idea一般是作为一个Java和Scala的开发工具来使用的,它的使用方法和Eclipse有一些不同,这里记录以下一些基本点. 1.创建项目 创建一个新项目的时候,用户必须选择一个 ...

  2. http头部信息解析

    HTTP 头部解释 1. Accept:告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type. 2. Accept-Chars ...

  3. mysql外键约束总结

    总结三种MySQL外键约束方式 如果表A的主关键字是表B中的字段,则该字段称为表B的外键,表A称为主表,表B称为从表.外键是用来实现参照完整性的,不同的外键约束方式将可以使两张表紧密的结合起来,特别是 ...

  4. LINUX下用C语言历遍目录 C语言列出目录 dirent.h在C/C++中的使用

    LINUX下历遍目录的方法一般是这样的打开目录->读取->关闭目录相关函数是opendir -> readdir -> closedir #include <dirent ...

  5. fopencookie函数详解

    今天看DPDK时,看到了fopencookie函数,以前基本没有用过该函数,乘此机会好好看看如何使用. 1. 函数头文件与函数原型 函数头文件: #include <stdio.h> 函数 ...

  6. WEB前端--CSS

    一.认识CSS 1.概念 CSS(Cascading Style Sheet,层叠样式表),可以将网页制作的更加绚丽多彩.它可以有效的对页面的布局.字体.颜色.背景和其它效果实现更加精确的控制. 2. ...

  7. 529A And Yet Another Bracket Sequence

    传送门 题目大意 给定有一个长度为n n的括号序列,现在有两种操作: 在任意一个位置插入有一个左括号或右括号 将末尾的一个括号放到最前面 可以对这个序列进行若干次操作,问在使括号序列合法的前提下,长度 ...

  8. wireshark抓取qq数据包

    抓包接口设置成本地连接 点击start,登录qq,输入oicq进行过滤qq包 找到第一个OICQ,点击后,点击oicq-IM software 可以看到自己登录的QQ号码为765343409 本机IP ...

  9. 日期多选插件Kalendae.js

    在项目中要实现日期多选的功能,于是在网上找到Kalendae.js,此文主要记录本人对于Kalendae.js的一些用法,以便以后查阅,希望对读者也有所帮助 主要内容如下: Kalendaejs一句话 ...

  10. 平台播放声音(ext.js)

    首先把需要的两个js文件放在public/core路径下 (文件已经上传到博客了) 音频文件放在文件一级目录 代码:JxCustom.loadAudio("wav/NG.wav") ...