java-多线程-CyclicBarrier(循环栅栏)

  • CyclicBarrier
CyclicBarrier barrier = new CyclicBarrier(8);
  1. CyclicBarrier 可以理解为我们田径比赛的起跑线,它定义了8个跑道
  2. 要求必须8个跑道都有人了才能跑
  3. 假如来了7人,那么7人都得在起跑线这里等着,等到凑够8人才能你跑
  4. 假如来了9人,那么从这9人中选出8人去跑,留下一人继续等到再凑够8人再一起跑
  5. 这就是CyclicBarrier的作用,它调用await()方法是起跑线规则生效
  6. await():阻塞当前线程,并监视被阻塞线程的数量,达到要求数量之后统一放行
  • 我们用一个简单的例子看一下
  1. 场景:我们现在要集合一个10小分队去打仗,要求所有人都到达集合点后一起出发
// 行军线程
public class ThreadMarch implements Runnable{
    // 姓名
    private String name;
    // 可以理解为集合地点
    private CyclicBarrier barrier;

    public ThreadMarch(String name, CyclicBarrier barrier) {
        this.name = name;
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            System.out.println(this.name+" 正在朝这里赶来。。。");
            Thread.sleep(2000);
            System.out.println(this.name+" 到达集合点!");
            // 等待其他队员;await()方法可以带参数,表示等待多长时间,如果到时间还没到那就不等了
            barrier.await();
            // 所有人都到了,开始出发
            System.out.println(this.name+" 出发了!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}
public static void main(String[] args) {
    // 创建一个线程池
    ExecutorService executor = Executors.newFixedThreadPool(12);
    // 创建一个10人小分队,barrier 就是我们对这10人规定的集合点
    CyclicBarrier barrier = new CyclicBarrier(10);
    try {
        executor.execute(new ThreadMarch("小明",barrier));
        executor.execute(new ThreadMarch("小强",barrier));
        executor.execute(new ThreadMarch("田鸡",barrier));
        executor.execute(new ThreadMarch("浩南",barrier));
        executor.execute(new ThreadMarch("呆鸡哥",barrier));
        executor.execute(new ThreadMarch("路飞",barrier));
        executor.execute(new ThreadMarch("李白",barrier));
        executor.execute(new ThreadMarch("一页书",barrier));
        executor.execute(new ThreadMarch("袁天罡",barrier));
        executor.execute(new ThreadMarch("大乔",barrier));

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        executor.shutdown();
    }
}

输出:
小明 正在朝这里赶来。。。
浩南 正在朝这里赶来。。。
呆鸡哥 正在朝这里赶来。。。
袁天罡 正在朝这里赶来。。。
一页书 正在朝这里赶来。。。
小强 正在朝这里赶来。。。
路飞 正在朝这里赶来。。。
大乔 正在朝这里赶来。。。
田鸡 正在朝这里赶来。。。
李白 正在朝这里赶来。。。
小明 到达集合点!
呆鸡哥 到达集合点!
袁天罡 到达集合点!
一页书 到达集合点!
浩南 到达集合点!
小强 到达集合点!
路飞 到达集合点!
大乔 到达集合点!
田鸡 到达集合点!
李白 到达集合点!
李白 出发了!
小明 出发了!
呆鸡哥 出发了!
一页书 出发了!
袁天罡 出发了!
小强 出发了!
浩南 出发了!
路飞 出发了!
大乔 出发了!
田鸡 出发了!

 

  1. 我们可以看到,所有人都到了集合地点以后才开始出发。
  2. 假如我们不使用 CyclicBarrier呢?那就不会等待,谁先到谁就出发了。如下:
public class ThreadMarch implements Runnable{
    // 姓名
    private String name;
    // 可以理解为集合地点
    private CyclicBarrier barrier;

    public ThreadMarch(String name, CyclicBarrier barrier) {
        this.name = name;
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            System.out.println(this.name+" 正在朝这里赶来。。。");
            Thread.sleep(2000);
            System.out.println(this.name+" 到达集合点!");
            // 等待其他队员;await()方法可以带参数,表示等待多长时间,如果到时间还没到那就不等了
//            barrier.await();
            // 所有人都到了,开始出发
            System.out.println(this.name+" 出发了!");
        } catch (InterruptedException e) {
            e.printStackTrace();
//        } catch (BrokenBarrierException e) {
//            e.printStackTrace();
        }
    }
}

输出:
小明 正在朝这里赶来。。。
浩南 正在朝这里赶来。。。
呆鸡哥 正在朝这里赶来。。。
田鸡 正在朝这里赶来。。。
袁天罡 正在朝这里赶来。。。
李白 正在朝这里赶来。。。
一页书 正在朝这里赶来。。。
小强 正在朝这里赶来。。。
路飞 正在朝这里赶来。。。
大乔 正在朝这里赶来。。。
小明 到达集合点!
小明 出发了!
呆鸡哥 到达集合点!
呆鸡哥 出发了!
田鸡 到达集合点!
田鸡 出发了!
浩南 到达集合点!
袁天罡 到达集合点!
袁天罡 出发了!
李白 到达集合点!
李白 出发了!
浩南 出发了!
一页书 到达集合点!
一页书 出发了!
小强 到达集合点!
大乔 到达集合点!
大乔 出发了!
路飞 到达集合点!
路飞 出发了!
小强 出发了!

 

  • CyclicBarrier与CountDownLatch比较
  1. CountDownLatch:一个线程(或者多个),等待另外N个线程完成某个事情之后才能执行;CyclicBarrier:N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
  2. CountDownLatch:一次性的;CyclicBarrier:可以重复使用。
  3. CountDownLatch基于AQS;CyclicBarrier基于锁和Condition。本质上都是依赖于volatile和CAS实现的。

你可能感兴趣的:(Java)