千家信息网

如何使用Java高并发编程CyclicBarrier

发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容介绍了"如何使用Java高并发编程CyclicBarrier"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,
千家信息网最后更新 2025年01月20日如何使用Java高并发编程CyclicBarrier

本篇内容介绍了"如何使用Java高并发编程CyclicBarrier"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

什么是CyclicBarrier

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

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

如何使用

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

/**demo 来源https://blog.csdn.net/lstcui/article/details/107389371  * 公众号【java金融】  */ 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();         }     } }

输出结果如下:

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

源码分析

结构组成

/** The lock for guarding barrier entry */ private final ReentrantLock lock = new ReentrantLock(); /** Condition to wait on until tripped */ private final Condition trip = lock.newCondition(); /** The number of parties */ private final int parties; /* The command to run when tripped */ private final Runnable barrierCommand; /** The current generation */ private Generation generation = new Generation();
  • lock:用于保护屏障入口的锁

  • trip :达到屏障并且不能放行的线程在trip条件变量上等待

  • parties :栅栏开启需要的到达线程总数

  • barrierCommand:最后一个线程到达屏障后执行的回调任务

  • generation:这是一个内部类,通过它实现CyclicBarrier重复利用,每当await达到最大次数的时候,就会重新new 一个,表示进入了下一个轮回。里面只有一个boolean型属性,用来表示当前轮回是否有线程中断。

主要方法

public int await() throws InterruptedException, BrokenBarrierException {     try {         return dowait(false, 0L);     } catch (TimeoutException toe) {         throw new Error(toe); // cannot happen     } }   * 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 {            //获取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();     } }

"如何使用Java高并发编程CyclicBarrier"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

线程 屏障 情况 时候 阻塞 方法 队列 循环 条件 主动 只有 地图 背景 背景音乐 音乐 变化 编程 最大 一代 人物 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 向数据库插入中文字段 erp软件开发电话 丰台区有名的软件开发诚信服务 网络安全控制不当言论 可用于存储数据库查询集的对象是 数据库只读怎么取消 不属于软件开发生命周期阶段 嘉定区电商软件开发联系方式 力控7.1关系数据库操作 cash 数据库 微盟数据库怎么样了 有诚信的软件开发培训 苏州办公系统软件开发定制费用 南京智运道合网络技术有限公司 物业管理服务器 软件开发功能大纲 花季我爱你服务器连接失败 山东爱卡族网络技术 faceit北美有哪些服务器 黑龙江互联网软件开发中心 宝坻区电子网络技术质量保证 网络安全预警方案 川美互联网科技 网络安全手抄报一等奖漂亮合集 怎么进服务器管理员模式语句 软件开发企业内部组织架构 银川网络安全工程师培训班 手机mx播放器怎么添加服务器 数据库登不上怎么回事 福清网络安全办公室
0