java并发编程之三--CyclicBarrier的使用

CyclicBarrier

  允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。

CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。

  实现原理:在CyclicBarrier的内部定义了一个Lock对象,每当一个线程调用await方法时,将拦截的线程数减1,然后判断剩余拦截数是否为初始值parties,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁。

构造方法 

CyclicBarrier(int parties)
创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。
CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。

方法

  • int await() 等待所有 parties已经在这个障碍上调用了 await 。
  • int await(long timeout, TimeUnit unit) 等待所有 parties已经在此屏障上调用 await ,或指定的等待时间过去。
  • int getNumberWaiting() 返回目前正在等待障碍的各方的数量。
  • int getParties() 返回旅行这个障碍所需的parties数量。
  • boolean isBroken() 查询这个障碍是否处于破碎状态。
  • void reset() 将屏障重置为初始状态。

测试

 1 import java.util.concurrent.CyclicBarrier;
 2 
 3 import concurrenttest.cyclicbarrier.thread.Thread_01;
 4 
 5 /**
 6  * CyclicBarrier 类测试
 7  * 允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环
 8  * ,因为它可以在等待的线程被释放之后重新使用。
 9  * 
10  * @author bc
11  * @data 2018年9月29日
12  */
13 public class RunTest_01 {
14 
15     public static void main(String[] args) {
16         /**
17          * 创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸, 当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。
18          */
19         CyclicBarrier cbRef = new CyclicBarrier(5, new Runnable() {
20             public void run() {
21                 // TODO Auto-generated method stub
22                 System.out.println("都到了");
23             }
24         });
25 
26         Thread_01[] threads = new Thread_01[5];
27         for (int i = 0; i < threads.length; i++) {
28             threads[i] = new Thread_01(cbRef);
29             threads[i].start();
30         }
31 
32     }
33 
34 }
RunTest_01
 1 import java.util.concurrent.BrokenBarrierException;
 2 import java.util.concurrent.CyclicBarrier;
 3 
 4 /**
 5  * 允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环
 6  * ,因为它可以在等待的线程被释放之后重新使用。
 7  * 
 8  * @author bc
 9  * @data 2018年9月29日
10  */
11 public class Thread_01 extends Thread {
12 
13     private CyclicBarrier cbRef;
14 
15     public Thread_01(CyclicBarrier cbRef) {
16         super();
17         this.cbRef = cbRef;
18     }
19 
20     @Override
21     public void run() {
22         try {
23             Thread.sleep((int) (Math.random() * 1000));
24             System.out.println(Thread.currentThread().getName() + "到了!" + System.currentTimeMillis());
25             // 等待所有 parties已经在这个障碍上调用了 await 。
26             cbRef.await();
27         } catch (InterruptedException e) {
28             // TODO Auto-generated catch block
29             e.printStackTrace();
30         } catch (BrokenBarrierException e) {
31             // TODO Auto-generated catch block
32             e.printStackTrace();
33         }
34     }
35 }
Thread_01

CountDownLatch和CyclicBarrier的比较

  1. CountDownLatch是线程组之间的等待,即一个(或多个)线程等待N个线程完成某件事情之后再执行;而CyclicBarrier则是线程组内的等待,即每个线程相互等待,即N个线程都被拦截之后,然后依次执行。
  2. CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。
  3. CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置。
  4. CountDownLatch不可以复用,而CyclicBarrier可以复用。

详见本人github:https://github.com/BrokenColor/java-demo 下的 cyclicbarrier-包中的测试

posted @ 2018-10-08 11:41  BrokenColor  阅读(12250)  评论(2编辑  收藏  举报