下面用一个小 demo,对 cyclicbarrier 有一个初步的印象。
public class test implements runnable{ //定义一个循环栅栏 private cyclicbarrier cyclicbarrier = new cyclicbarrier(3,this); //存放每个线程的数据 private blockingqueue list = new arrayblockingqueue(3); public void count() { //运行 3 个线程 for(int i = 0;i< 3;i++){ new thread(new runnable() { public void run() { //这里可以存放更复杂的操作,比如查询 sql、写入 excel 等等 random r = new random(); int a = r.nextint(100); system.out.println(线程 + thread.currentthread().getname() + 获得数字: + a); list.add(a); try { //线程到达栅栏后,等待 cyclicbarrier.await(); }catch (exception e){ e.printstacktrace(); } } }).start(); } } //这里就是线程一起跨过栅栏后执行的任务 public void run() { int result = 0; for (integer i: list) { result += i; } system.out.println(result); } public static void main(string[] args){ test test = new test(); test.count(); }}这个 demo 中一共 3 个线程,每个线程都随机获取一个数字(在实际生产代码中会有更复杂的操作),最后将每个线程获取的数字相加后打印最后的结果。
源码分析内部类cyclicbarrier 的一个内部类,generation 被翻译成为“代”。当这一代的所有线程都到达栅栏后可以开启下一代,所以才被成为循环栅栏。broken 属性表示栅栏是否被打破了。
private static class generation { boolean broken = false;}属性与构造函数//可重入的 reentrantlock 锁,非公平锁private final reentrantlock lock = new reentrantlock();//lock 的条件队列private final condition trip = lock.newcondition();//线程的数量private final int parties;//所有线程到达后,可执行的方法private final runnable barriercommand;//当前代private generation generation = new generation();//当前代还需要等待线程的数量private int count;public cyclicbarrier (int parties) { //调用 2 个参数的构造函数 this(parties, null);}public cyclicbarrier(int parties, runnable barrieraction) { //检查线程的数量是否小于 0 if (parties 0l) //等待指定的时间 nanos = trip.awaitnanos(nanos); } catch (interruptedexception ie) { //出了异常且当前代没有打破栅栏,那么打破栅栏并且抛出异常 if (g == generation && ! g.broken) { breakbarrier(); throw ie; } else { //中断当前线程 thread.currentthread().interrupt(); } } //检查 if (g.broken) throw new brokenbarrierexception(); //不是当前的代 if (g != generation) return index; //等待超时了 if (timed && nanos <= 0l) { breakbarrier(); throw new timeoutexception(); } } } finally { //解锁,出队 lock.unlock(); }}dowait() 的运行被分成了 2 部分:
最后一个线程的时候,进入运行 barriercommand 方法的流程,并且进入下一代。前面的其他线程都进入循环中,将线程添加到 trip 的条件队列中,等待最后一个线程将它们唤醒。
nextgeneration()//cyclicbarrier.nextgeneration() private void nextgeneration() { trip.signalall(); count = parties; generation = new generation();}cyclicbarrier 为什么会一代结束后可以开始下一代,就靠这个 nextgeneration() 方法,它干了三件事:
trip.signalall() 方法将 trip() 条件队列中的线程全部转移到 aqs 队列中去。aqs 队列中出队是在 lock.unlock() 的时候。将线程的数量重置。初始化一个新的代。总结cyclicbarrier 使用了两个队列,一个条件队列,一个 aqs 队列,在 trip.await() 出进入条件队列。当最后一个线程到达栅栏出的时候,条件队列中的线程全部移动到 aqs 队列中,要注意的是最后一个线程并没有进入 aqs 队列中。在 lock.unlock() 的时候 aqs 队列中的线程出队。
cyclicbarrier 基于 reentrantlock 和 condition 实现同步线程的逻辑。
智能版Babolat AeroPro Drive Play球拍
医疗废物在线监测系统加强医废监管
芯片短缺可能导致第一季度全球减产近100万辆轻型车辆
iPhone8什么时候上市?iPhone8最新消息:iPhone8工程测试机遭泄露,5.8寸屏分辨率创新高!
Vishay推出背面绝缘的TrenchFET功率MOSFET
CyclicBarrier 任务实践
荣耀V30 PRO的多摄协同录制功能怎么样
智能物联网企业触景无限入选2023年度高成长企业TOP100榜单
XG1590射频、中频、音频放大电路的应用
自动驾驶商业落地现状与未来发展前景
一种新颖的完全断续箝位电流模式功率因数校正电路
华为与中兴:既非兄弟,也非死敌,而更类似于“国共合作”
NVIDIA DRIVE Orin 助力腾势 N7 实现全场景智能驾驶辅助
工程监测多通道振弦传感器无线采集仪采集与发送时间间隔设置
电机损耗高,你知道问题在哪吗?
ICCAD 2022 | 芯动高端DDR、Chiplet硬核产品成果亮眼
微软竟然发布了自己的Linux
路由器EMC测试的流程及需要提供的资料
常见的区块链+供应链金融模式
电动滑板DIY图解