概念
-
从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。
-
它的作用就是会让所有线程都等待完成后才会继续下一步行动。
-
举个例子,就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。
构造方法
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
解析:
- parties 是参与线程的个数
- 第二个构造方法有一个 Runnable 参数,这个参数的意思是最后一个到达线程要做的任务
重要方法
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
解析:
- 线程调用 await() 表示自己已经到达栅栏
- BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时
下面我们就来自定义实现一个CyclicBarrier
代码如下:
public class KaneCyclicBarrier {
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private int count =0; //批次
private final int parties; //多少线程准备就绪?
private Object generation = new Object();
public KaneCyclicBarrier(int parties) {
this.parties = parties;
}
public void await(){
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Object g = generation;
int index = ++count;
if (index == parties) {
nextGeneration();
return;
}
while (true) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(g!=generation){
return;
}
}
}finally {
lock.unlock();
}
}
public void nextGeneration(){
condition.signalAll();
count=0;
generation = new Object();
}
}
测试一下,代码如下:
public class CyclicBarrier_Demo {
public CyclicBarrier_Demo() {
}
public static void main(String[] args) throws InterruptedException {
KaneCyclicBarrier barrier = new KaneCyclicBarrier(4);
for(int i = 0; i < 100; ++i) {//假设有100个任务,每次只能有固定数量的线程去执行,可以使用这个
(new Thread(() -> {
barrier.await();
System.out.println("任务开始执行");
})).start();
Thread.sleep(500L);
}
}
}
CyclicBarrier 使用场景
可以用于多线程计算数据,最后合并计算结果的场景。
CyclicBarrier 与 CountDownLatch 区别
- CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
- CountDownLatch减计数,CyclicBarrier加计数。
- CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。