CyclicBarrier是栅栏,效果就是让多个线程都执行到某个指定的点之后,再一起继续执行。与CountDownLatch有点类似,最大的区别是CyclicBarrier可以循环使用。

这里举例两个场景,一个是斗地主,需要三个玩家都入场之后才可以开始。 另一个是赛马,多匹马一起跑,最先到达终点的算赢。这里用线程分别表示玩家和马。

三人斗地主代码如下:
(需要三个玩家入场之后才能发牌)

public class Player extends Thread {private static int count = 1;private final int id = count++;private CountDownLatch latch;public Player(CountDownLatch latch) {this.latch = latch;}@Overridepublic void run() {System.out.println("【玩家" + id + "】已入场");latch.countDown();//计数器减1}public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(3); //初始化计数器System.out.println("牌局开始, 等待玩家入场...");new Player(latch).start();//启动玩家线程new Player(latch).start();启动玩家线程new Player(latch).start();启动玩家线程latch.await();//阻塞等待计数器为0System.out.println("玩家已到齐, 开始发牌...");}}

结果如下:

牌局开始, 等待玩家入场…
【玩家2】已入场
【玩家1】已入场
【玩家3】已入场
玩家已到齐, 开始发牌…

如果不使用CountDownLatch,我们直接注释掉//latch.await(); 看结果

牌局开始, 等待玩家入场…
【玩家1】已入场
【玩家2】已入场
玩家已到齐, 开始发牌…
【玩家3】已入场

三个玩家没凑齐就发牌了。

原理:CountDownLatch
构造函数中创建了Sync这个内部类的对象

    public CountDownLatch(int count) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = new Sync(count);}

内部类Sync继承了AbstractQueuedSynchronizer 简称AQS,AQS可以理解成是java里面用java代码实现的Synchronize,而不是由jvm去实现的。在AQS里面维护了一个state ,以及一个同步队列和多个条件队列
想要锁但是没获取到锁的线程,都在同步队列里面等着,获取到锁但是没有满足执行条件的,都在条件队列里面等着。

调用latch.await();的线程,被加入到同步队列里面等着,直到计数器为0释放锁。

它的内部提供了一个计数器,在构造闭锁时必须指定计数器的初始值,且计数器的初始值必须大于0。另外它还提供了一个countDown方法来操作计数器的值,每调用一次countDown方法计数器都会减1,直到计数器的值减为0时就代表条件已成熟,所有因调用await方法而阻塞的线程都会被唤醒。这就是CountDownLatch的内部机制
CountDownLatch只有一个带参构造器,必须传入一个大于0的值作为计数器初始值,否则会报错。可以看到在构造方法中只是去new了一个Sync对象并赋值给成员变量sync。和其他同步工具类一样,CountDownLatch的实现依赖于AQS,它是AQS共享模式下的一个应用。CountDownLatch实现了一个内部类Sync并用它去继承AQS,这样就能使用AQS提供的大部分方法了。下面我们就来看一下Sync内部类的代码。

//同步器
private static final class Sync extends AbstractQueuedSynchronizer {//构造器Sync(int count) {setState(count);}//获取当前同步状态int getCount() {return getState();}//尝试获取锁//返回负数:表示当前线程获取失败//返回零值:表示当前线程获取成功, 但是后继线程不能再获取了//返回正数:表示当前线程获取成功, 并且后继线程同样可以获取成功protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;}//尝试释放锁protected boolean tryReleaseShared(int releases) {for (;;) {//获取同步状态int c = getState();//如果同步状态为0, 则不能再释放了if (c == 0) {return false;}//否则的话就将同步状态减1int nextc = c-1;//使用CAS方式更新同步状态if (compareAndSetState(c, nextc)) {return nextc == 0;}}}
}

赛马游戏的代码如下:


`
public class Horse implements Runnable {

private static int counter = 0;
private final int id = counter++;
private int strides = 0;
private static Random rand = new Random(47);
private static CyclicBarrier barrier;public Horse(CyclicBarrier CyclicBarrier) {this.barrier = CyclicBarrier;
}@Override
public void run() {try {while (!Thread.interrupted()) {synchronized (this) {//赛马每次随机跑几步strides += rand.nextInt(3);}barrier.await();//线程在此进行等待}} catch (Exception e) {e.printStackTrace();}
}public String tracks() {StringBuilder s = new StringBuilder();for (int i = 0; i < getStrides(); i++) {s.append("*");}s.append(id);return s.toString();
}public synchronized int getStrides() {return strides;
}public String toString() {return "Horse " + id + " ";
}

}

赛马过程

public class HorseRace implements Runnable {private static final int FINISH_LINE = 75;private static List<Horse> horses = new ArrayList<Horse>();private static ExecutorService exec = Executors.newCachedThreadPool();@Overridepublic void run() {StringBuilder s = new StringBuilder();//打印赛道边界for(int i = 0; i < FINISH_LINE; i++) {s.append("=");}System.out.println(s);//打印赛马轨迹for(Horse horse : horses) {System.out.println(horse.tracks());}//判断是否结束for(Horse horse : horses) {if(horse.getStrides() >= FINISH_LINE) {System.out.println(horse + "won!");exec.shutdownNow();return;}}//休息指定时间再到下一轮try {TimeUnit.MILLISECONDS.sleep(200);} catch(InterruptedException e) {System.out.println("barrier-action sleep interrupted");}}public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(7, new HorseRace()); //需要到达的线程数,以及线程到达之后需要执行的线程for(int i = 0; i < 7; i++) {Horse horse = new Horse(barrier);horses.add(horse);exec.execute(horse);}}}

执行结果

如下
===============
**0
**1
*2
**3
*4
**5
*6
。。。。。省略n个
===============
***********0
************1
********2
***********3
**********4
***************5
************6
Horse 5 won!

执行barrier.await();的线程进行等待,直到所有计数器到达设置的值,然后继续执行下一轮。

从赛马游戏看CyclicBarrier,从斗地主看CountDownLatch相关推荐

  1. 利用CyclicBarrier实现赛马游戏

    赛马游戏 前言 最近在看CountDownLatch和CyclicBarrier相关的锁知识,看到网上有通过CyclicBarrier特性实现一个赛马游戏,觉得很有意思,就把他搬运过来. 背景 多匹马 ...

  2. html5 游戏前景怎么样,独家 HTML5游戏目前究竟怎么样?看完这篇文章,你或许会清晰很多...

    原标题:独家 HTML5游戏目前究竟怎么样?看完这篇文章,你或许会清晰很多 文/DataEye CEO 汪祥斌 从5月份白鹭的10亿估值,到最近悟空间.山水地.火缘步甲的千万级以上的融资,我们可以感受 ...

  3. 计算机专业男生宿舍,实拍大学男生宿舍,男生们不是玩电脑游戏,就是瘫在床上看手机!...

    大学环境很自由,课程不多,闲余时间很多,所以很多男生都会呆在宿舍里,不是玩游戏,就是躺在床上看手机,如果不是吃饭,他们可以在宿舍上呆上一整天. 男生宿舍一般都是这样的,干净整洁在这里是不存在的,男生们 ...

  4. C初阶必写的C语言小游戏—扫雷,一看就会,看完就能写

    目录 一.前言 二.资源环境的配置 三.游戏整体构思 1.游戏的开始与结束(菜单) 2.创建二维数组用来布置雷和排查雷的信息 3.初始化棋盘 4.打印棋盘 5.布置雷 6.排查雷 四.所有代码及效果展 ...

  5. CyclicBarrier实现赛马游戏

    CyclicBarrier实现赛马游戏 import java.util.ArrayList; import java.util.List; import java.util.Random; impo ...

  6. JAVA2048感受心得_2048游戏心得大分享 不看你就OUT啦

    这次舒尘给大家带来的分享是2048这款游戏的心得哦,那些高分玩家们对于这款游戏又什么心得体会,有什么习惯方式呢?跟小编一起来看看今天的分享2048游戏心得大分享 不看你就OUT啦. 大神总结心得第一条 ...

  7. 【游戏客户端】5分钟看懂商店拍卖系统

    [游戏客户端]5分钟看懂商店&拍卖系统     大家好,我是Lampard~~     最近刚研究完图的最短路径算法[20分钟回顾四大寻路算法],现在终于有空腾出时间写一篇游戏系统的分享了. ...

  8. 模特赛马java课程设计_Thinking in Java---Concurrent包下的新构件学习+赛马游戏仿真...

    Java5的java.util.concurrent包下引入了大量的用于解决并发问题的新类:相对于前面那些基础的线程同步和通信的方法,这些新类是一种更高层次上的抽象,使用起来还是比较容易的.这篇博客就 ...

  9. hm55主板支持最大内存_内存频率取决于CPU还是主板?内存频率看主板支持还是看CPU支持?...

    内存频率取决于CPU还是主板还是内存自身?高频内存在日常使用确实感受不到性能差异,不过在部分游戏中,确实对游戏帧数有一定的提升.对于准备新装机用户,不少用户发现CPU和主板都有内存支持频率参数,可能有 ...

最新文章

  1. aspose.cells 无法读取公式值_隐藏 Excel表格、公式的9种方法
  2. linux oracle 查看版本号,Linux下如何查看版本信息
  3. thinkpad x230评测_全新改变超长续航 ThinkPad X230评测
  4. MYSQL使用inner join 进行 查询/删除/修改示例
  5. 职责链模式 php,php Chain of Responsibility 职责链模式
  6. star rating
  7. 代码中有个get是啥意思_是时候秀一波了,甩掉get和set,Lombok让代码更简洁
  8. dockerHub登录失败
  9. linux中板子烧写环境配置,3、在Linux下搭建51单片机的开发烧写环境(makefile版)...
  10. windows server 2016 DC重置用户密码报错
  11. @Scope作用域代理的应用:@RefreshScope注解实现动态刷新配置的底层原理与实现
  12. 防范蠕虫式勒索软件病毒攻击的安全预警通告
  13. Visio 直角连接线增加直角拐弯的方法, 取消自动附着,取消自动捕捉
  14. 单细胞分析实录(16): 非负矩阵分解(NMF)检测细胞异质性
  15. 【kubernetes】k8s的job和cronjob详细说明【job、cronjob(cj)、descheduler(pod均衡)】
  16. cocos creator Android 接入Google登陆sdk
  17. 专访枫叶租车联合创始人兼CEO金晓磊:枫叶的精神内核是热爱和创新
  18. 聊一聊 MySQL 中的事务及其实现原理
  19. “互联网+”大学生创新创业大赛产业命题赛道命题方向分析
  20. Salesforce的多态存储和SAP C4C的元数据存储仓库

热门文章

  1. 华为平板M3能用鸿蒙吗,华为平板M3怎么样 麒麟950处理器搭配快充只要1888!
  2. 功能: Form窗口最大化时,控件相对位置变化的问题 (学习日记2016-12-23)
  3. 高校或企业开源软件镜像站【汇总】2022.5.8
  4. 图片验证码不显示解决方案
  5. 警告:关于电磁辐射对孕妇的危害。
  6. 用Python底层编写进行计量经济分析(一):多元线性回归(参数估计、T检验、拟合优度、F检验)
  7. char和varchar区别
  8. CRM管理系统添加客户
  9. 【PATB1041】考试座位号(题解+拓展)
  10. PC VR游戏的CPU性能分析与优化