0%

CyclicBarrier

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。把一个大任务分成N个小任务让不同线程去执行,负责每个小任务的线程完成任务后阻塞挂起,完成任务数加1(内部操作,无需手动);当完成任务总数达到N时,执行 barrierAction 任务。


应用场景

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


测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CyclicBarrierTest {
static CyclicBarrier cyclicBarrier = new CyclicBarrier(3,
() -> System.out.println("三个臭皮匠顶个诸葛亮"));

public static void main(String[] args) {
int parties = cyclicBarrier.getParties();
for (int i = 0; i < parties; i++) {
new Thread(() -> {
try {
System.out.println("线程 " + Thread.currentThread().getName() + " 的任务已完成,等待...");
// 执行完任务后等待
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}

测试结果


原理分析

下面是 CyclicBarrier 的源码,可以看到它利用 ReentrantLock(可重入锁) 和 Condition 实现了线程等待与线程间通信,其实使用 CyclicBarrier 除了构造方法,关键就在 await() 方法中,虽然 CyclicBarrier 是加法计数,却不需要我们手动操作。


CyclicBarrier和CountDownLatch的区别

CountDownLatch CyclicBarrier
减计数方式 加计数方式
计算为0时释放所有等待的线程 计数达到指定值时释放所有等待线程
计数为0时,无法重置 计数达到指定值时,计数置为0重新开始
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞
计算为0时释放所有等待的线程 计数达到指定值时释放所有等待线程
不可重复利用 可重复利用(reset)