免费模板下载网站,网站建设联系,百度做的网站,网站建设系统教程写在开头
面试官#xff1a;同学#xff0c;AQS的原理知道吗#xff1f; 我#xff1a;学过一点#xff0c;抽象队列同步器#xff0c;Java中很多同步工具都是基于它的… 面试官#xff1a;好的#xff0c;那其中CyclicBarrier学过吗#xff1f;讲一讲它的妙用吧 我同学AQS的原理知道吗 我学过一点抽象队列同步器Java中很多同步工具都是基于它的… 面试官好的那其中CyclicBarrier学过吗讲一讲它的妙用吧 我啊这个这个我平时写代码没用过… 面试官那你回去再学学吧
随着Java的国内竞争环境逐渐激烈面试时遇到很多奇葩的问题也是越来越多以上是模拟的一个面试场景同学们看下你们能答得上来不
什么是CyclicBarrier
在过去的几天里我们基于AQS学习了不少内容其中基于AQS构建的同步工具类也学了Semaphore信号量和CountDownLatch倒计时器甚至于也手撕过同步器今天我们继续来学习另外一个同步类CyclicBarrier
CyclicBarrier循环屏障让一组线程到达一个屏障也可以叫同步点时被阻塞直到最后一个线程到达屏障时屏障才会开门所有被屏障拦截的线程才会继续干活。
CyclicBarrier的原理
在CyclicBarrier有两个成员变量分别为partiescount前者代表每次拦截的线程数量后者是初始化时保持和parties相等的计数标识每有一个线程执行到同步点时count减1当count值变为0时说明所有线程都走到了同步点这时就可以尝试执行我们在构造方法中设计的任务啦。
【源码解析1】
//每次拦截的线程数
private final int parties;
//计数器
private int count;//一个参数的构造
public CyclicBarrier(int parties) {this(parties, null);
}
//多参构造parties为拦截线程数barrierAction这个 Runnable会在 CyclicBarrier 的计数器为 0 的时候执行用来完成更复杂的任务。
public CyclicBarrier(int parties, Runnable barrierAction) {if (parties 0) throw new IllegalArgumentException();this.parties parties;this.count parties;this.barrierCommand barrierAction;
}每个线程通过调用await方法告诉CyclicBarrier已经到达屏障然后进行阻塞等待知道count等于0所有线程都到达了屏障因此我们跟入await方法的源码中去看一下。
【源码解析2】
public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);} catch (TimeoutException toe) {throw new Error(toe); // cannot happen}
}
//await方法内部继续调用dowait方法实现功能
private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock this.lock;// 锁住lock.lock();try {final Generation g generation;if (g.broken)throw new BrokenBarrierException();// 如果线程中断了抛出异常if (Thread.interrupted()) {//打破屏障breakBarrier();throw new InterruptedException();}// cout减1int index --count;// 当 count 数量减为 0 之后说明最后一个线程已经到达栅栏了也就是达到了可以执行await 方法之后的条件if (index 0) { // trippedboolean ranAction false;try {final Runnable command barrierCommand;if (command ! null)command.run();ranAction true;// 将 count 重置为 parties 属性的初始化值// 唤醒之前等待的线程// 下一波执行开始nextGeneration();return 0;} finally {if (!ranAction)breakBarrier();}}// loop until tripped, broken, interrupted, or timed outfor (;;) {try {if (!timed)trip.await();else if (nanos 0L)nanos trip.awaitNanos(nanos);} catch (InterruptedException ie) {if (g generation ! g.broken) {breakBarrier();throw ie;} else {// Were about to finish waiting even if we had not// been interrupted, so this interrupt is deemed to// belong to subsequent execution.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(boolean timed, long nanos)可以通过时间参数来设置阻塞的时间默认为false在这个方法内部每次线程调用await后都会进行–count操作直到index为0时会去执行command然后唤醒线程继续向下执行CyclicBarrier 的计数器可以通过reset()方法重置所以它能处理循环使用的场景。
CyclicBarrier的使用
大致的了解了CyclicBarrier的原理之后我们写个小demo测试一下它如何使用
【代码示例】
public class Test {public static void main(String[] args) {int numberOfThreads 3; // 线程数量CyclicBarrier barrier new CyclicBarrier(numberOfThreads, () - {// 当所有线程都到达障碍点时执行的操作System.out.println(所有线程都已到达屏障进入下一阶段);});for (int i 0; i numberOfThreads; i) {new Thread(new Task(barrier), Thread (i 1)).start();}}static class Task implements Runnable {private final CyclicBarrier barrier;public Task(CyclicBarrier barrier) {this.barrier barrier;}Overridepublic void run() {try {System.out.println(Thread.currentThread().getName() 正在屏障处等待);barrier.await(); // 等待所有线程到达障碍点System.out.println(Thread.currentThread().getName() 已越过屏障.);} catch (Exception e) {e.printStackTrace();}}}
}输出
Thread 2 正在屏障处等待
Thread 1 正在屏障处等待
Thread 3 正在屏障处等待
所有线程都已到达屏障进入下一阶段
Thread 3 已越过屏障.
Thread 1 已越过屏障.
Thread 2 已越过屏障.结尾彩蛋
如果本篇博客对您有一定的帮助大家记得留言点赞收藏呀。原创不易转载请联系Build哥 如果您想与Build哥的关系更近一步还可以关注“JavaBuild888”在这里除了看到《Java成长计划》系列博文还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等欢迎您的加入