CyclicBarrier的使用

允许任意数量的线程 await 等待,直到所有合作线程都达到某个点,然后所有线程从该点继续执行

构造函数

java 复制代码
public CyclicBarrier(int parties) {
    this(parties, null);
}

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}
  • parties 并行等待的线程个数
  • barrierAction 所有线程都执行等待后,需要运行的代码

方法

java 复制代码
// 当前线程一直等待到 parties 个线程都调用了 await 方法
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}
// 当前线程等待到 parties 个线程都调用了 await 方法 或者超过 timeout 时间
public int await(long timeout, TimeUnit unit)
    throws InterruptedException,
           BrokenBarrierException,
           TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}

// 线程等待是否被破坏了,比如超时,或者线程 interrupted
public boolean isBroken() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return generation.broken;
    } finally {
        lock.unlock();
    }
}
// 重置,CyclicBarrier 可以重复利用,不用重新生成对象
public void reset() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        breakBarrier();   // break the current generation
        nextGeneration(); // start a new generation
    } finally {
        lock.unlock();
    }
}
// 获取还剩多少个线程没有执行到等待 await
public int getNumberWaiting() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return parties - count;
    } finally {
        lock.unlock();
    }
}

使用示例

java 复制代码
public class Main {
    public static final int PARTIES = 3;
    public static final int LEN = 5;
    private Integer[][] mData;
    CyclicBarrier mCyclicBarrier;

    public static void main(String[] args) {
        Main main = new Main();
        main.done();
    }

    private void done() {
        Random random = new Random();
        // 创建 CyclicBarrier 3个线程等待,执行等待后执行的 runnable
        mCyclicBarrier = new CyclicBarrier(PARTIES, () -> {
            // 分别打印 3 个 int 类型数组
            for (int i = 0; i < PARTIES; i++) {
                for (int j = 0; j < LEN; j++) {
                    System.out.print(mData[i][j] + " ");
                }
                System.out.println();
            }
        });
        // 二维数组,3个线程处理一个 5个 数字大小的排序
        mData = new Integer[PARTIES][LEN];

        for (int i = 0; i < PARTIES; i++) {
            mData[i] = new Integer[LEN];
            for (int j = 0; j < LEN; j++) {
                // 构建数据
                mData[i][j] = 100 * i + random.nextInt(50);
            }
            // 启动 3个 线程
            new Thread(new Worker(mData[i], mCyclicBarrier)).start();
        }
    }

    private static class Worker implements Runnable {


        Integer[] mData;
        CyclicBarrier mCyclicBarrier;

        public Worker(Integer[] data, CyclicBarrier cyclicBarrier) {
            mData = data;
            mCyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            Arrays.sort(mData); // 进行排序
            System.out.println(Thread.currentThread().getName() + " : finish...");
            try {
                mCyclicBarrier.await();
                System.out.println(Thread.currentThread().getName() + " await over ...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

输出

erlang 复制代码
Thread-0 : finish...
Thread-2 : finish...
Thread-1 : finish...
0 20 27 41 43 
102 124 126 136 148 
210 233 234 240 246 
Thread-1 await over ...
Thread-0 await over ...
Thread-2 await over ...

说明

  • 同步辅助工具,它允许一组线程全部互相等待以到达一个公共的障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,该线程方有时必须互相等待。 该屏障称为循环屏障,因为它可以在释放等待线程之后重新使用。
  • CyclicBarrier支持可选的Runnable命令,该命令在障碍中的最后一个线程到达之后但在释放任何线程之前,每个障碍点运行一次。 此屏障操作对于在任何一方继续之前更新共享状态很有用
  • CyclicBarrier 对失败的同步尝试使用全无损坏模型:如果线程由于中断,失败或超时而过早离开障碍点,则所有其他在该障碍点等待的线程也会通过BrokenBarrierException(或InterruptedException)异常离开 他们也大约同时被打断了。
  • 内存一致性影响:调用await()之前的线程中的操作发生在 CyclicBarrier 操作的一部分之前,而其他操作又发生在其他线程中的相应await()成功返回之后的操作之前。
相关推荐
非 白13 分钟前
【Java】代理模式
java·开发语言·代理模式
Good Note24 分钟前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
我就是我3521 小时前
记录一次SpringMVC的406错误
java·后端·springmvc
向哆哆1 小时前
Java应用程序的跨平台性能优化研究
java·开发语言·性能优化
ekkcole2 小时前
windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry
java·windows·jar
handsomestWei2 小时前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城2 小时前
03 Python字符串与基础操作详解
java·开发语言·python
伯牙碎琴2 小时前
二、Spring Framework基础:IoC(控制反转)和DI(依赖注入)
java·spring·log4j
菲力蒲LY2 小时前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis
南宫生3 小时前
力扣每日一题【算法学习day.130】
java·学习·算法·leetcode