CyclicBarrier介绍
字面意思回环栅栏(循环屏障),通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
CyclicBarrier的使用
构造方法
//parties表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,//然后当前线程被阻塞。public CyclicBarrier(int parties) {this(parties, null);}//barrierAction,用于在线程都到达屏障时(线程个数是等于parties的时候),优先执行的任务。//构造方法里面的count就是屏障的资源数,而parties就是屏障数量的备份,用于重用的public CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();this.parties = parties;this.count = parties;this.barrierCommand = barrierAction;}
重要方法
//await 告诉屏障当前线程已经准备好了,//指定数量的线程全部调用await()方法时,这些线程不再阻塞//BrokenBarrierException表示栅栏已经被破坏,//破坏的原因可能是其中一个线程await()时被中断或者超时public int await() throws InterruptedException, BrokenBarrierException { }public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {}//重置屏障拦截的线程数量public void reset() {}
CyclicBarrier应用场景
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。
//保存每个学生的平均成绩private ConcurrentHashMap<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() {@Overridepublic 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) {TT t = new TT();t.count();}
CyclicBarrier与CountDownLatch的区别
- CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset() 方法重置
- CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法
- CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程
- CountDownLatch一般用于一个或多个线程,等待其他线程执行完任务后,再执行。CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行
- CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果
- CyclicBarrier是通过ReentrantLock的”独占锁”和Conditon来实现一组线程的阻塞唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现
