java多线程系列:通过对战游戏学习CyclicBarrier

CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。

这篇文章将介绍CyclicBarrier这个同步工具类的以下几点

  1. 通过案例分析
  2. 两种不同构造函数测试
  3. CyclicBarrier和CountDownLatch的区别
  4. await方法及源码分析。

需求

继上一篇CountDownLatch模拟游戏加载后,现在用户点击开始按钮后,需要匹配包括自己在内的五个玩家才能开始游戏,匹配玩家成功后进入到选择角色阶段。当5位玩家角色都选择完毕后,开始进入游戏。进入游戏时需要加载相关的数据,待全部玩家都加载完毕后正式开始游戏。

解决方案

从需求中可以知道,想要开始游戏需要经过三个阶段,分别是

  1. 匹配玩家
  2. 选择角色
  3. 加载数据

在这三个阶段中,都需要互相等待对方完成才能继续进入下个阶段。 
这时可以采用CyclicBarrier来作为各个阶段的节点,等待其他玩家到达,在进入下个阶段。

定义继承Runnable的类

这里名称就叫做StartGame,包含两个属性

private String player;
private CyclicBarrier barrier;

通过构造函数初始化两个属性

public StartGame(String player, CyclicBarrier barrier) {this.player = player;this.barrier = barrier;
}

run方法如下

public void run() {try {System.out.println(this.getPlayer()+" 开始匹配玩家...");findOtherPlayer();barrier.await();System.out.println(this.getPlayer()+" 进行选择角色...");choiceRole();System.out.println(this.getPlayer()+" 角色选择完毕等待其他玩家...");barrier.await();System.out.println(this.getPlayer()+" 开始游戏,进行游戏加载...");loading();System.out.println(this.getPlayer()+" 游戏加载完毕等待其他玩家加载完成...");barrier.await();start();} catch (Exception e){e.printStackTrace();}
}

其他的方法findOtherPlayer()、choiceRole()等待使用

Thread.sleep()

来模拟花费时间

编写测试代码

CyclicBarrier有两个构造函数,如下

public CyclicBarrier(int parties) {}
public CyclicBarrier(int parties, Runnable barrierAction) {}

先来看看一个参数的构造函数

CyclicBarrier(int parties)

public static void main(String[] args) throws IOException {CyclicBarrier barrier = new CyclicBarrier(5);Thread player1 = new Thread(new StartGame("1",barrier));Thread player2 = new Thread(new StartGame("2",barrier));Thread player3 = new Thread(new StartGame("3",barrier));Thread player4 = new Thread(new StartGame("4",barrier));Thread player5 = new Thread(new StartGame("5",barrier));player1.start();player2.start();player3.start();player4.start();player5.start();System.in.read();
}

测试结果如下

CyclicBarrier(int parties, Runnable barrierAction)

CyclicBarrier barrier = new CyclicBarrier(5);

替换为

CyclicBarrier barrier = new CyclicBarrier(5, () -> {try {System.out.println("阶段完成,等待2秒...");Thread.sleep(2000);System.out.println("进入下个阶段...");} catch (InterruptedException e) {e.printStackTrace();}});

再来看看效果

可以看到在到达某个节点时,会执行实例化CyclicBarrier时传入的Runnable对象。而且每一次到达都会执行一次。

CyclicBarrier和CountDownLatch的区别

CountDownLatchCyclicBarrier
计数为0时,无法重置计数达到0时,计数置为传入的值重新开始
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响调用await()方法计数减一,若减一后的值不等于0,则线程阻塞
不可重复使用可重复使用

await方法

public int await(){}
public int await(long timeout, TimeUnit unit){}

无参的await方法这里就不做介绍了,主要介绍下有参的await方法。 
有参的await方法传入两个参数,一个是时间、另一个是时间单位 
当调用有参的await方法时会出现下方两个异常

java.util.concurrent.TimeoutException
java.util.concurrent.BrokenBarrierException

TimeoutException异常是指调用await方法后等待时间超过传入的时间,此时会将CyclicBarrier的状态变成broken,其他调用await方法将会抛出BrokenBarrierException异常,这时的CyclicBarrier将变得不可用,需要调用reset()方法重置CyclicBarrier的状态。

为什么这么说? 
源码分析一波就可以看出来了 
不管是有参还是无参的await方法都是调用CyclicBarrierdowait(boolean timed, long nanos)方法,这个方法代码太长了,截取部分贴出来

private int dowait(boolean timed, long nanos){//加锁、try catch代码final Generation g = generation;//判断栅栏的状态if (g.broken)throw new BrokenBarrierException();//...省略int index = --count;//(index == 0) 时的代码,省略for (;;) {try {if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {}//判断栅栏的状态if (g.broken)throw new BrokenBarrierException();if (g != generation)return index;//判断是否是定时的,且已经超时了if (timed && nanos <= 0L) {//打破栅栏的状态breakBarrier();throw new TimeoutException();}}//解锁
}

在代码的尾部进行判断当前等待是否已经超时,如果是会调用breakBarrier()方法,且抛出TimeoutException异常,下面是breakBarrier()的代码

private void breakBarrier() {generation.broken = true;count = parties;trip.signalAll();
}

代码中将broken状态置为true,表示当前栅栏移除损坏状态,且重置栅栏数量,然后唤醒其他等待的线程。此时被唤醒的线程或者其他线程进入dowait方法时,都会抛出BrokenBarrierException异常案例源代码地址:

https://github.com/rainbowda/learnWay/tree/master/learnConcurrency/src/main/java/com/learnConcurrency/utils/cyclicBarrier

觉得不错的点个Star,谢谢


原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/520932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Wi-Fi 6到底有什么特别?

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 甜草莓责编 | 阿秃▋ 什么是Wi-Fi 6 &#xff1f;Wi-Fi 6&#xff0c;是Wi-Fi联盟给IEEE Std. P802.11ax起的别名。众所周知&#xff0c;以前我们的Wi-Fi都是叫作802.11a/b/n/g/ac/ax之类的名字。这种命名方式实在容易让人…

matlab直流电机pid调速仿真,直流电机双闭环PID调速系统仿真设计

目录直流电机双闭环PID调速系统仿真1 转速、电流双闭环直流调速系统的组成及工作原理2 双闭环调速系统的动态数学模型3 调节器的设计3.1 电流调节器的设计3.2 转速调节器的设计4 搭建模型5 参数计算5.1 参数的直接计算5仿真具体参数6 仿真结果7 结束语8 参考文献摘要在工程的应…

【小技巧】桌面图标出现蓝色问号的怎么办?

【背景】 今天因为要联调前端所以用SVN更新了一下前端的代码&#xff0c;结果没想到桌面图标全部变成了带着蓝色问号的&#xff0c;吓了自己一跳。查了一下之后顺利解决了&#xff0c;不过以防万一记录一下解决方法。 【内容】 解决步骤&#xff1a;首先确定是SVN的问题导致了…

恒强制版系统980_速来围观 | 恒强制版小图高级功能讲解

点击蓝字关注我们 Spring comes小图是用自定义的动作来定义使用者色码(120-183)。小图的主要构成如下图&#xff1a;1. 模块色数属性模块色数有如下规则&#xff1a;(1) 小于100(一般填1)的小图为普通小图【980修改】&#xff1b;(2) 小于200大于100(一般填101)的小图为提花小图…

读懂这篇文章,你的阿里技术面就可以过关了 | Apache RocketMQ 101

在美国的大学课程中&#xff0c;101是所有课程中的第一门&#xff0c;是新生入学后的必修课程。阿里巴巴中间件技术专家刘振东在上周的Apache RocketMQ开发者沙龙北京站的活动上&#xff0c;进行了主题为《ApacheRocketMQ 101》的分享&#xff0c;帮助开发者从0开始学习 Apache…

Nacos 计划发布v0.2版本,进一步融合Dubbo和SpringCloud生态

在近期的Aliware Open Source 成都站的活动上&#xff0c;阿里巴巴高级工程师邢学超&#xff08;于怀&#xff09;分享了Nacos v0.2的规划和进度&#xff0c;并对Nacos v0.3的控制台进行了预览。Nacos v0.2将进一步融入Duboo和Spring Cloud生态&#xff0c;帮助开发者更好的在微…

你还在疯狂加班打码?兄dei,不如跟我学做超融合吧!

纵观过去十年&#xff0c;媒体、娱乐、交通、银行、保险、医疗、旅游、物流等行业&#xff0c;无一不打上了数字化的烙印。据统计&#xff0c;一百多年前&#xff0c;公司的平均寿命是67年&#xff1b;而在当今的数字化时代&#xff0c;则锐减至15年。 除此之外&#xff0c;更有…

你只差这两步 | 将Sentinel 控制台应用于生产环境

这是围绕 Sentinel 的使用场景、技术对比和实现、开发者实践等维度推出的系列文章的第四篇。 第一篇回顾&#xff1a; Dubbo 的流量防卫兵 | Sentinel如何通过限流实现服务的高可用性 - 传送门 第二篇回顾&#xff1a; RocketMQ 的保险丝| Sentinel 如何通过匀速请求和冷启动…

eclipse分级,分级列表显示 - bieshixuan的个人博客 - OSCHINA - 中文开源技术交流社区...

这是个效果图设计思想是&#xff0c;使用左右两个tableview分别展示NSArray * _allArr;NSMutableArray * _rightArr;UITableView * _leftTableView;UITableView * _rightTableView;初始化_arr [{"全部":[ "棉花", "小麦", "水稻", &q…

分布式消息规范 OpenMessaging 1.0.0-preview 发布

OpenMessaging 是由阿里巴巴牵头发起&#xff0c;由 Yahoo、滴滴、Streamlio、微众银行、Datapipeline 等公司共同发起创建的分布式消息规范&#xff0c;其目标在于打造厂商中立&#xff0c;面向 Cloud Native &#xff0c;同时对流计算以及大数据生态友好的下一代分布式消息标…

腾讯云重磅发布系列自研产品,自研服务器星星海为云而生

今日在腾讯全球数字生态大会成都峰会上&#xff0c;腾讯云重磅发布系列自研产品&#xff0c;包括腾讯自研第四代数据中心T-block产品家族、第一款真正为云而生的自研服务器“星星海”等基础产品&#xff0c;结合现场发布的弹性容器服务、无服务器等自研产品&#xff0c;腾讯云正…

wsimport将wsdl生成java 调用时碰到的一个问题Could not initialize Service

在一个采用了XFire作为WebService框架Web项目中&#xff0c;添加由JDK1.6 wsimport命令生成的一个WebService客户端调用&#xff0c;在客户端调用时出现了如下问题 log4j:WARN No appenders could be found for logger (org.codehaus.xfire.jaxws.Provider). log4j:WARN Pleas…

服务化改造实践(二)| Dubbo + Kubernetes

“没有最好的技术&#xff0c;只有最合适的技术。”我想这句话也同样适用于微服务领域&#xff0c;没有最好的服务框架&#xff0c;只有最适合自己的服务改造。在Dubbo的未来规划中&#xff0c;除了保持自身技术上的领先性&#xff0c;关注性能&#xff0c;大流量&#xff0c;大…

电子技术基础数字部分第六版_大部分数字图书馆技术特点与应用分析

数字图书馆是一个开放式的硬件和软件的集成平台&#xff0c;通过对技术和产品的集成&#xff0c;把当前大量的各种文献载体数字化&#xff0c;将它们组织起来在网上服务。从理论上讲&#xff0c;数字图书馆是一种引入管理和应用数字化技术的方法&#xff0c;它的主要特点有&…

腾讯云与智慧产业总裁汤道生:产业互联网是一场“持久战”

“产业互联网是一场‘持久战’&#xff0c;腾讯希望和合作伙伴一起参与转型&#xff0c;让每一个产业都变身为智慧产业&#xff0c;实现数字化、网络化和智能化。”10月29日&#xff0c;在腾讯全球数字生态大会成都峰会上&#xff0c;腾讯公司高级执行副总裁、云与智慧产业事业…

NLP领域中更有效的迁移学习方法

在深度学习领域&#xff0c;迁移学习&#xff08;transfer learning&#xff09;是应用比较广的方法之一。该方法允许我们构建模型时候不光能够借鉴一些其它科研人员的设计的模型&#xff0c;还可以借用类似结构的模型参数&#xff0c;有些类似于站在巨人的肩膀上进行深入开发。…

使用wsimport将wsdl生成java

使用管理员打开cmd wsimport -encoding utf-8 -keep -s D:\temp -p com.lamcy.webService -verbose http://服务地址?wsdl -encoding : 指定编码格式 -keep&#xff1a;是否生成java源文件 -d&#xff1a;指定.class文件的输出目录 -s&#xff1a;指定.java文件的输出目录…

使用python创建自己的第一个神经网络模型吧!

神经网络&#xff08;NN&#xff09;&#xff0c;也被称为人工神经网络&#xff08;ANN&#xff09;&#xff0c;是机器学习领域中学习算法的子集&#xff0c;大体上借鉴了生物神经网络的概念。目前&#xff0c;神经网络在计算机视觉、自然语言处理等领域应用广泛。德国资深机器…

百度现场面试:JVM+算法+Redis+数据库!(三面)| CSDN博文精选

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 中琦2513转自 &#xff5c; CSDN博客责编 | 阿秃百度一面&#xff08;现场&#xff09;自我介绍Java中的多态为什么要同时重写hashcode和equalsHashmap的原理Hashmap如何变线程安全&#xff0c;每种方式的优缺点垃圾回收机制…

语义分割概念及应用介绍

近年来&#xff0c;以深度学习为中心的机器学习技术引起了人们的关注。比如自动驾驶汽车已经逐渐成为可能&#xff0c;但在整个深度学习过程&#xff0c;需要算法识别和学习作为原始数据提供的图像&#xff0c;在这一过程中&#xff0c;应用到了语义分割技术。下面让我们来看看…