CyclicBarrier
基本使用
CyclicBarrier:循环屏障,用来进行线程协作,等待线程满足某个计数,才能触发自己执行
常用方法:
public CyclicBarrier(int parties, Runnable barrierAction)
:用于在线程到达屏障 parties 时,执行 barrierAction- parties:代表多少个线程到达屏障开始触发线程任务
- barrierAction:线程任务
public int await()
:线程调用 await 方法通知 CyclicBarrier 本线程已经到达屏障
与 CountDownLatch 的区别:CyclicBarrier 是可以重用的
应用:可以实现多线程中,某个任务在等待其他线程执行完毕以后触发
1 | public static void main(String[] args) { |
实现原理
成员属性
全局锁:利用可重入锁实现的工具类
1
2
3
4// barrier 实现是依赖于Condition条件队列,condition 条件队列必须依赖lock才能使用
private final ReentrantLock lock = new ReentrantLock();
// 线程挂起实现使用的 condition 队列,当前代所有线程到位,这个条件队列内的线程才会被唤醒
private final Condition trip = lock.newCondition();线程数量:
1
2private final int parties; // 代表多少个线程到达屏障开始触发线程任务
private int count; // 表示当前“代”还有多少个线程未到位,初始值为 parties当前代中最后一个线程到位后要执行的事件:
1
private final Runnable barrierCommand;
代:
1
2
3
4
5
6
7// 表示 barrier 对象当前 代
private Generation generation = new Generation();
private static class Generation {
// 表示当前“代”是否被打破,如果被打破再来到这一代的线程 就会直接抛出 BrokenException 异常
// 且在这一代挂起的线程都会被唤醒,然后抛出 BrokerException 异常。
boolean broken = false;
}构造方法:
1
2
3
4
5
6
7
8
9public CyclicBarrie(int parties, Runnable barrierAction) {
// 因为小于等于 0 的 barrier 没有任何意义
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
// 可以为 null
this.barrierCommand = barrierAction;
}
CountDownLatch与CyclicBarrier的使用场景与区别对比
CountDownLatch的使用场景:
在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作,这个时候就可以使用CountDownLatch。 CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了;
CyclicBarrier的使用场景:
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如我们用一个Excel保存了用户所有有很那个流水,每个Sheet保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里面的银行流水,都执行完成之后,得到每个sheet中的日均银行流水。最后,再用barrierAcition用这些线程的计算结果,计算出整个Excel的日均银行流水。
cyclicBarrier和CountDownLatch的区别是什么
- a. CountDownLatch简单的说就是一个线程等待,直到它所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。
- b. CyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行!
- c.CountDownLatch的计数器只能使用一次,而cyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能够处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程重新执行一次;