CyclicBarrier介绍

字面意思回环栅栏(循环屏障),通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。

CyclicBarrier的使用

构造方法

  1. //parties表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,
  2. //然后当前线程被阻塞。
  3. public CyclicBarrier(int parties) {
  4. this(parties, null);
  5. }
  6. //barrierAction,用于在线程都到达屏障时(线程个数是等于parties的时候),优先执行的任务。
  7. //构造方法里面的count就是屏障的资源数,而parties就是屏障数量的备份,用于重用的
  8. public CyclicBarrier(int parties, Runnable barrierAction) {
  9. if (parties <= 0) throw new IllegalArgumentException();
  10. this.parties = parties;
  11. this.count = parties;
  12. this.barrierCommand = barrierAction;
  13. }

重要方法

  1. //await 告诉屏障当前线程已经准备好了,
  2. //指定数量的线程全部调用await()方法时,这些线程不再阻塞
  3. //BrokenBarrierException表示栅栏已经被破坏,
  4. //破坏的原因可能是其中一个线程await()时被中断或者超时
  5. public int await() throws InterruptedException, BrokenBarrierException { }
  6. public int await(long timeout, TimeUnit unit)
  7. throws InterruptedException,
  8. BrokenBarrierException,
  9. TimeoutException {
  10. }
  11. //重置屏障拦截的线程数量
  12. public void reset() {
  13. }

CyclicBarrier应用场景

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。

  1. //保存每个学生的平均成绩
  2. private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
  3. private ExecutorService threadPool = Executors.newFixedThreadPool(3);
  4. private CyclicBarrier cb = new CyclicBarrier(3, () -> {
  5. int result = 0;
  6. Set<String> set = map.keySet();
  7. for (String s : set) {
  8. result += map.get(s);
  9. }
  10. System.out.println("三人平均成绩为:" + (result / 3) + "分");
  11. });
  12. public void count() {
  13. for (int i = 0; i < 3; i++) {
  14. threadPool.execute(new Runnable() {
  15. @Override
  16. public void run() {
  17. //获取学生平均成绩
  18. int score = (int) (Math.random() * 40 + 60);
  19. map.put(Thread.currentThread().getName(), score);
  20. System.out.println(Thread.currentThread().getName()
  21. + "同学的平均成绩为:" + score);
  22. try {
  23. //执行完运行await(),等待所有学生平均成绩都计算完毕
  24. cb.await();
  25. } catch (InterruptedException | BrokenBarrierException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. });
  30. }
  31. }
  32. public static void main(String[] args) {
  33. TT t = new TT();
  34. t.count();
  35. }

CyclicBarrier与CountDownLatch的区别

  1. CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset() 方法重置
  2. CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法
  3. CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程
  4. CountDownLatch一般用于一个或多个线程,等待其他线程执行完任务后,再执行。CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行
  5. CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果
  6. CyclicBarrier是通过ReentrantLock的”独占锁”和Conditon来实现一组线程的阻塞唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现