写在开头

面试官:同学,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减1
int index = --count;
// 当 count 数量减为 0 之后说明最后一个线程已经到达栅栏了,也就是达到了可以执行await 方法之后的条件
if (index == 0) { // tripped
boolean 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 out
for (;;) {
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 {
// We're 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;
} @Override
public 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成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

面试官:说一说CyclicBarrier的妙用!我:这个没用过的更多相关文章

  1. 【对线面试官】CountDownLatch和CyclicBarrier的区别

    <对线面试官>系列目前已经连载31篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...

  2. 面试官就是要问我SpringMVC的源码,差点顶不住!

    <对线面试官>系列目前已经连载22篇啦!有深度风趣的系列! [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 & ...

  3. 【对线面试官】Kafka基础入门

    <对线面试官>系列目前已经连载33篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...

  4. 一线大厂面试官最喜欢问的15道Java多线程面试题

    前言 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得更多职位,那么你应该准备很多关于多线程的问题. 他们会问面试者很多令人混淆的Java线程问题.面试官只是想确信面试者 ...

  5. 飞越面试官(二)--JUC

    大家好!我是本号唯一官方指定没头屑的小便--怕屁林. JUC是什么东西?我相信很多经验尚浅的小伙伴部分都会为之一懵,我也是,三个字母都会读,连在一起就不知道在说什么,其实如果把它的全称写出来,“jav ...

  6. 100道Java高频面试题(阿里面试官整理)

    我分享文章的时候,有个读者回复说他去年就关注了我的微信公众号,打算看完我的所有文章,然后去面试,结果我后来很长时间不更新了...所以为了弥补一直等我的娃儿们,给大家的金三银四准备了100道花时间准备的 ...

  7. 每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

    面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

  8. 面试官的七种武器:Java篇

    起源 自己经历过的面试也不少了,互联网的.外企的,都有.总结一下这些面试的经验,发现面试官问的问题其实不外乎几个大类,玩不出太多新鲜玩意的.细细想来,面试官拥有以下七种武器.恰似古龙先生笔下的武侠世界 ...

  9. 关键词:ACM & 大小端 & 面试官

    关于“ACM” fender0107401 :面试了一个在ACM拿过奖的人 我问了他几个问题: 读取数组中的一个元素,计算复杂度是多少,回答不清楚. 往链表里面存一个数,不排序的情况下,计算复杂度是多 ...

  10. Android开发面试经——6.常见面试官提问Android题②(更新中...)

    版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http://blog.csdn.net/fi ...

随机推荐

  1. redis分片sharding实现原理

    为什么集群? 通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取.Redis是一个很好的Cache工具.大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿,在 ...

  2. Twitter推特 api接口 获取trending趋势搜索关键词 python数据采集

    iDataRiver平台 https://www.idatariver.com/zh-cn/ 提供开箱即用的Twitter公开数据采集API,供用户按需调用. 接口使用详情请参考Twitter接口文档 ...

  3. 案例8:将"picK"的大小写互换

    最终输出结果为PICk. 需要先计算两个字母之间的间隔,比如a和A之间的间隔为多少. 然后在将大写字母转换为小写字母,加上间隔的值: 将小写字母转换为大写字母,减去间隔的值. 示例代码如下: #def ...

  4. Java处理子父级菜单的方式二

    处理存在子父级关系的数据是写代码的过程中常见的操作,前面讲解过使用递归的方法来做, 可以参考这篇博客 https://www.cnblogs.com/yilangcode/p/16831867.htm ...

  5. inputNextFocus vue - js 跳转 下一个 tab

    inputNextFocus vue - js 跳转 下一个 tab <template> <Input v-model="val1" ref="inp ...

  6. Windows逆向之配置虚拟机环境

    安装虚拟机环境 首先下载吾爱破解论坛专用版虚拟机软件VMWare Workstation 12,注册成功:再通过虚拟机启动论坛提供的WinXP系统镜像,在我的win11上完美运行. 实现文件互传 为了 ...

  7. Android webview只加载10%且出现白屏问题排查解决

    原文:Android webview只加载10%且出现白屏问题排查解决 - Stars-One的杂货小窝 问题 有一个主页面,布局里是包含的一个自定义Webview,并且注入了些原生的方法进去,供原生 ...

  8. springboot打jar包

    参考,欢迎点击原文:https://www.jianshu.com/p/84883627db67(简书) https://www.cnblogs.com/dk1024/p/10802007.html( ...

  9. python高级技术(IO模型)

    一 IO模型介绍 Linux环境下的network IO * blocking IO           阻塞IO    * nonblocking IO      非阻塞IO    * IO mul ...

  10. 记录--H5 实现拍照选景框效果

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 在实际项目中,遇到了需要唤起手机摄像头拍照的需求,最开始是通过<input type="file" hid ...