前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JUC并发包系列:CyclicBarrier

JUC并发包系列:CyclicBarrier

作者头像
张云飞Vir
发布2022-09-29 12:21:05
5640
发布2022-09-29 12:21:05
举报
文章被收录于专栏:写代码和思考

介绍

CyclicBarrier 一种同步辅助工具,它允许一组线程相互等待以达到共同的障碍点。 CyclicBarriers 在涉及固定大小的线程组的程序中很有用,这些线程组必须偶尔相互等待。 屏障被称为循环的,因为它可以在等待线程被释放后重新使用。

主要方法

代码语言:javascript
复制
构造方法:
  public CyclicBarrier(int parties, Runnable barrierAction)
  参数:
    int parties, 在障碍被触发之前必须调用await的线程数
    Runnable barrierAction,当障碍被触发时执行的动作,如果没有动作则为null

void await() 方法:
  进入等待的休眠状态。直到发生以下情况之一:
    最后一个线程到达;
    或者其他一些线程中断当前线程;
    或者其他一些线程中断了其他等待线程之一;
    或者其他一些线程在等待屏障时超时;
    或者其他一些线程在此屏障上调用reset 。


void reset()
  将屏障重置为其初始状态。

示例用法

示例:7 个线程 同时(并行)去找龙珠,当7个都达到时,触发一个动作 "凑齐"

代码示例

代码语言:javascript
复制
public class CyclicBarrierDemo {

    public static void main(String[] arr) throws InterruptedException {
        // 第一个参数:int parties, 在障碍被触发之前必须调用await的线程数
        // 第二个参数:Runnable barrierAction,当障碍被触发时执行的动作,如果没有动作则为null
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, new Runnable() {
            @Override
            public void run() {
                System.out.printf("七颗龙珠已经凑齐,召唤神龙\n");
            }
        });

        // 连续的触发 7 次
        for (int i = 0; i < 7; i++) {
            new Thread(new Hero(cyclicBarrier)).start();
        }

        Thread.sleep(5000);
    }

    public static class Hero implements Runnable {
        CyclicBarrier cyclicBarrier ;

        public Hero(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.printf("[%s] 找到一颗龙珠... \n",Thread.currentThread().getName());
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

写在后面

  • CyclicBarrier是基于ReentrantLock重入锁实现的,当然ReentrantLock也是基于AQS实现的
  • 成员变量说明:
代码语言:javascript
复制
重要成员变量

    / /可以理解为初始化时 需要阻塞的任务个数
    private final int parties;
    / /剩余需要等待的任务个数,初始值为parties,直到为0时依次唤醒所有被阻塞的任务线程。
    private int count;

    / /每次对“栅栏”的主要成员变量进行变更操作,都应该加锁
    private final ReentrantLock lock = new ReentrantLock();
    / /用于阻塞和唤醒任务线程
   private final Condition trip = lock.newCondition();

    / /在所有线程被唤醒前,需要执行的一个Runable对应的run方法
    private final Runnable barrierCommand;
    / /用于表示“栅栏”当前的状态
    private Generation generation = new Generation();
  • 它内部实现使用了 ReentrantLock ,代码都在 lock 锁的控制范围内,不会出现并发情况。
代码语言:javascript
复制
  private final ReentrantLock lock = new ReentrantLock();
  • 内部实现使用了 Condition。会调用Condition的singalAll方法,唤醒所有在屏障前面等待的线程,让其开始继续执行;
代码语言:javascript
复制
  private final Condition trip = lock.newCondition();
  • 用 Generation 代表 多少代。在 reset 时 重新生成一个 Generation

参考

https://blog.csdn.net/chongbin007/article/details/91359728 https://www.jianshu.com/p/043ac5689002

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 示例用法
  • 写在后面
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档