CyclicBarrier 源码分析之怎么卷死 CountDownLatch
CyclicBarrier 是什么?
CyclicBarrier
一般称为栅栏
、屏障,是一种多线程同步工具。
常常和 CountDownLatch
一起作比较,因为都属于用于一组线程等待的工具。
不同于 CountDownLatch
常用于协调线程等待一组工作线程,且工作线程到达后做一次通知并继续执行,CyclicBarrier
人如其名的是一组线程相互等待全部到达指定处后,再全部继续执行。
CyclicBarrier
更高级的是:
-
允许重用,执行完成后或手动重置即可重新使用;
CountDownLatch
直接报废。 -
允许执行回调逻辑,一般是最后一个到达栅栏的线程自调用。我们可以用这个特性在业务逻辑中执行收尾工作。
-
出现问题可破坏当前分代(通知其他线程),重置进行下一次。不同于
CountDownLatch
达到指定条件处后就不关心结果,CyclicBarrier
必须等待在栅栏。如果某个工作线程在到达前出现异常,那就需要人为处理重置。当然出现异常、超时等情况也会自动破坏当前使用,但是注意并不能直接进行下一次使用,必须手动重置。
CyclicBarrier 怎么用?
CountDownLatch:几道锁的保险箱 (juejin.cn) cue 到 CyclicBarrier
说打开保险锁后,就不能再用了。
允许重用
亲信当然希望开锁拿钱跑路以后,老板回来检查就不会发现。
private static void normal() throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3);
if (!barrier.isBroken()) {
System.out.println("保险箱:安全保护中");
}
System.out.println("亲信们:不成功便成仁!!!!!");
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new MyFollower(barrier));
thread.start();
}
Thread.sleep(1000);
if (!barrier.isBroken()) {
System.out.println("保险箱:安全保护中");
System.out.println("老板:很好,这东西不错");
}
}
private static class MyFollower implements Runnable {
private CyclicBarrier barrier;
public MyFollower(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
System.out.println("亲信:输入密码ing");
try {
barrier.await();
} catch (InterruptedException e) {
System.out.println("临死前:骂骂咧咧地退出了游戏");
} catch (BrokenBarrierException e) {
System.out.println("OS:傻子,这都输入错了");
}
System.out.println("亲信:成了!!!!!");
}
}
保险箱:安全保护中
亲信们:不成功便成仁!!!!!
亲信:输入密码ing
亲信:输入密码ing
亲信:输入密码ing
亲信:成了!!!!!
亲信:成了!!!!!
亲信:成了!!!!!
保险箱:安全保护中
老板:很好,这东西不错
亲信被杀(中断)、输入错了(主动破坏)、输入慢了(超时)的情况下,关我保险锁什么事?
由于内部线程中断、或主动破坏都是校验一个布尔值,因此这种情况下其他线程无法知道什么原因导致破坏。
简单实现代码(真实情况肯定是需要更完善的协调和处理的)
private static void normal() throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3);
if (!barrier.isBroken()) {
System.out.println("保险箱:安全保护中"