CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 提供的操作:
CyclicBarrier(int parties)
// 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
CyclicBarrier(int parties, Runnable barrierAction)
// 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
int await()
// 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
int await(long timeout, TimeUnit unit)
// 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
int getNumberWaiting()
// 返回当前在屏障处等待的参与者数目。
int getParties()
// 返回要求启动此 barrier 的参与者数目。
boolean isBroken()
// 查询此屏障是否处于损坏状态。
void reset()
// 将屏障重置为其初始状态。
案例:参见比赛的运动员都准备好了,比赛才能开始。
package com.lchtest.juc.assistant;
import java.util.Random;
import java.util.concurrent.*;
public class CyclicBarrierTest1 {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () ->{
System.out.println("裁判打响了发令枪!");
});
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(new Runner(barrier, "1号选手"));
executor.execute(new Runner(barrier, "2号选手"));
executor.execute(new Runner(barrier, "3号选手"));
/*barrier.reset();
executor.submit(new Runner(barrier, "4号选手"));
executor.submit(new Runner(barrier, "5号选手"));
executor.submit(new Runner(barrier, "6号选手"));*/
executor.shutdown();
}
}
class Runner implements Runnable{
private CyclicBarrier barrier;
private String name;
public Runner(CyclicBarrier barrier, String name){
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(8));
// barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待
System.out.println(name + "准备好了.");
barrier.await();
} catch (Exception e){
e.printStackTrace();
}
System.out.println(name + " 起跑!");
}
}
CyclicBarrier与CountDownLatch的区别
这两个类都可以实现一组线程在到达某个条件之前进行等待,它们内部都有一个计数器,当计数器的值不断的减为0的时候所有阻塞的线程将会被唤醒。
区别在于:
- CyclicBarrier的计数器由自己控制,CountDownLatch的计数器则由使用者来控制
- 在CyclicBarrier中线程调用await方法不仅会将自己阻塞还会将计数器减1,而在CountDownLatch中线程调用await方法只是将自己阻塞而不会减少计数器的值。
- CountDownLatch只能拦截一轮,而CyclicBarrier可以实现循环拦截。一般来说用CyclicBarrier可以实现CountDownLatch的功能,而反之则不能。至于何时使用CyclicBarrier,何时使用CountDownLatch,看情况决定