您好,欢迎访问一九零五行业门户网

Java中CyclicBarrier循环屏障怎么应用

一、简介cyclicbarrier 字面意思回环栅栏(循环屏障),它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,cyclicbarrier可以被重用。
cyclicbarrier 作用是让一组线程相互等待,当达到一个共同点时,所有之前等待的线程再继续执行,且 cyclicbarrier 功能可重复使用。
二、cyclicbarrier的使用构造方法:
// parties表示屏障拦截的线程数量,每个线程调用 await 方法告诉 cyclicbarrier 我已经到达了屏障,然后当前线程被阻塞。 public cyclicbarrier(int parties) // 用于在线程到达屏障时,优先执行 barrieraction,方便处理更复杂的业务场景(该线程的执行时机是在到达屏障之后再执行)
重要方法:
//屏障 指定数量的线程全部调用await()方法时,这些线程不再阻塞// brokenbarrierexception 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时public int await() throws interruptedexception, brokenbarrierexceptionpublic int await(long timeout, timeunit unit) throws interruptedexception, brokenbarrierexception, timeoutexception//循环 通过reset()方法可以进行重置
cyclicbarrier 应用场景利用 cyclicbarrier 可以用于多线程计算数据,最后合并计算结果的场景。
利用 cyclicbarrier的计数器能够重置,屏障可以重复使用的特性,可以支持类似“人满发车”的场景
模拟合并计算场景利用 cyclicbarrier 可以用于多线程计算数据,最后合并计算结果的场景。
public class cyclicbarriertest2 { //保存每个学生的平均成绩 private conc urrenthashmap<string, integer> map=new concurrenthashmap<string,integer>(); private executorservice threadpool= executors.newfixedthreadpool(3); private cyclicbarrier cb=new cyclicbarrier(3,()->{ int result=0; set<string> set = map.keyset(); for(string s:set){ result+=map.get(s); } system.out.println("三人平均成绩为:"+(result/3)+"分"); }); public void count(){ for(int i=0;i<3;i++){ threadpool.execute(new runnable(){ @override public void run() { //获取学生平均成绩 int score=(int)(math.random()*40+60); map.put(thread.currentthread().getname(), score); system.out.println(thread.currentthread().getname() +"同学的平均成绩为:"+score); try { //执行完运行await(),等待所有学生平均成绩都计算完毕 cb.await(); } catch (interruptedexception | brokenbarrierexception e) { e.printstacktrace(); } } }); } } public static void main(string[] args) { cyclicbarriertest2 cb=new cyclicbarriertest2(); cb.count(); }}
模拟“人满发车”的场景利用cyclicbarrier的计数器能够重置,屏障可以重复使用的特性,可以支持类似“人满发车”的场景
public class cyclicbarriertest3 { public static void main(string[] args) { atomicinteger counter = new atomicinteger(); threadpoolexecutor threadpoolexecutor = new threadpoolexecutor( 5, 5, 1000, timeunit.seconds, new arrayblockingqueue<>(100), (r) -> new thread(r, counter.addandget(1) + " 号 "), new threadpoolexecutor.abortpolicy()); cyclicbarrier cyclicbarrier = new cyclicbarrier(5, () -> system.out.println("裁判:比赛开始~~")); for (int i = 0; i < 10; i++) { threadpoolexecutor.submit(new runner(cyclicbarrier)); } } static class runner extends thread{ private cyclicbarrier cyclicbarrier; public runner (cyclicbarrier cyclicbarrier) { this.cyclicbarrier = cyclicbarrier; } @override public void run() { try { int sleepmills = threadlocalrandom.current().nextint(1000); thread.sleep(sleepmills); system.out.println(thread.currentthread().getname() + " 选手已就位, 准备共用时: " + sleepmills + "ms" + cyclicbarrier.getnumberwaiting()); cyclicbarrier.await(); } catch (interruptedexception e) { e.printstacktrace(); }catch(brokenbarrierexception e){ e.printstacktrace(); } } }}
输出结果:
3 号  选手已就位, 准备共用时: 78ms0
1 号  选手已就位, 准备共用时: 395ms1
5 号  选手已就位, 准备共用时: 733ms2
2 号  选手已就位, 准备共用时: 776ms3
4 号  选手已就位, 准备共用时: 807ms4
裁判:比赛开始~~
4 号  选手已就位, 准备共用时: 131ms0
3 号  选手已就位, 准备共用时: 256ms1
2 号  选手已就位, 准备共用时: 291ms2
1 号  选手已就位, 准备共用时: 588ms3
5 号  选手已就位, 准备共用时: 763ms4
裁判:比赛开始~~
三、cyclicbarrier 源码分析cyclicbarrier 流程主要是的流程:
获取锁 如果 count != 0 就进入阻塞;
进入阻塞之前,首先需要进入条件队列,然后释放锁,最后阻塞;
如果 count != 0 会进行一个唤醒,将所有的条件队列中的节点转换为阻塞队列;
被唤醒过后会进行锁的获取,如果锁获取失败,会进入 lock 的阻塞队列;
如果锁获取成功,进行锁的释放,以及唤醒,同步队列中的线程。
下面是一个简单的流程图:
下面是具体的一些代码调用的流程:
几个常见的问题?1.一组线程在触发屏障之前互相等待,最后一个线程到达屏障后唤醒逻辑是如何实现的. 唤醒的过程是通过调用 java.util.concurrent.locks.condition#signalall唤醒条件队列上的所有节点。
2.删栏循环使用是如何实现的? 实际上一个互斥锁 reentrantlock 的条件队列和阻塞队列的转换。
3.条件队列到同步队列的转换实现逻辑 ? 转换过程中,首先会先将条件队列中所有的阻塞线程唤醒,然后会去获取 lock 如果获取失败,就进入同步队列。
cyclicbarrier 与 countdownlatch的区别countdownlatch的计数器只能使用一次,而cyclicbarrier的计数器可以使用reset() 方法重置。所以cyclicbarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次
cyclicbarrier还提供getnumberwaiting(可以获得cyclicbarrier阻塞的线程数量)、isbroken(用来知道阻塞的线程是否被中断)等方法。
countdownlatch会阻塞主线程,cyclicbarrier不会阻塞主线程,只会阻塞子线程。
countdownlatch和cyclicbarrier都能够实现线程之间的等待,只不过它们侧重点不同。countdownlatch一般用于一个或多个线程,等待其他线程执行完任务后,再执行。cyclicbarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行。
cyclicbarrier 还可以提供一个 barrieraction,合并多线程计算结果。
cyclicbarrier是通过reentrantlock的独占锁和conditon来实现一组线程的阻塞唤醒的,而countdownlatch则是通过aqs的“共享锁”实现
以上就是java中cyclicbarrier循环屏障怎么应用的详细内容。
其它类似信息

推荐信息