1 引言
少侠在之前的一篇博客介绍闭锁CountDownLatch
的时候有提到CyclicBarrier
,那么它究竟是什么呢?本篇文章和你们一起揭开它神秘的面纱。
关于CountDownLatch
的原理和用法可以阅读下篇,附传送门↓:
Java并发编程(三):CountDownLatch(闭锁)原理及最佳实践 从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。
它的作用就是会让所有线程都等待完成后才会继续下一步行动。
举个例子,就像我们打王者荣耀,每个人的宽带网速不同,游戏开始受限于每个人进入游戏的时机,只有当所有人都进入游戏才会开局,这里的开局就是CyclicBarrier
(这里仅仅是举例,并不代表王者荣耀游戏开局就是通过CyclicBarrier
实现的)。
2 基本用法
2.1 构造方法:
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
说明:
- parties表示参与的线程个数
- 第二个构造方法有个Runnable类型的参数,表示当所有线程都完成后再继续进行的任务。
2.2 常用方法
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
说明:
- 线程调用
await()
表示自己已经到达栅栏 -
BrokenBarrierException
表示栅栏已经被破坏,破坏的原因可能是其中一个线程await()
时被中断或者超时
2.3 一个小栗子
假设A、B、C、D、E、F六个人约好了今天去春游,把预约的车子比喻成CyclicBarrier
,必须六个人都到了才能开始发车,只要缺一个人,其他先到达的人必须等待。如何实现这个场景呢?
来看代码:
/**
* @author Carson
* @date 2020/4/14 19:13
*/
public class Main {
public static void main(String[] args) {
int threadNum = 6;
//初始化循环栅栏,含6个线程,当6个线程都到栅栏位置则执行这里的“集合完毕...”
final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum, new Runnable() {
@Override
public void run() {
System.out.println("\r\n" + Thread.currentThread().getName() + " 集合完毕,准备发车..."+"\r\n");
}
});
//初始化线程池
final ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(threadNum,
new BasicThreadFactory.Builder().daemon(true).build());
for (int i = 0; i < threadNum; i++) {
//提交线程
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 前来集合...");
try {
//每次提交的时候调用await()操作,通知系统自己已经到达栅栏处
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
//当所有线程都冲破栅栏之后继续执行该操作
System.out.println(Thread.currentThread().getName() + " 开始春游...");
}
});
}
}
}
输出结果也好理解:
pool-1-thread-3 前来集合...
pool-1-thread-5 前来集合...
pool-1-thread-1 前来集合...
pool-1-thread-4 前来集合...
pool-1-thread-2 前来集合...
pool-1-thread-6 前来集合...
pool-1-thread-6 集合完毕,准备发车...
pool-1-thread-6 开始春游...
pool-1-thread-3 开始春游...
pool-1-thread-2 开始春游...
pool-1-thread-4 开始春游...
pool-1-thread-1 开始春游...
pool-1-thread-5 开始春游...
由结果可以看出,6个人全部到齐的时候才执行集合完毕的操作,并且该操作是由最后一个冲破栅栏的线程执行的(如本例是pool-1-thread-6完成执行的)。当所有人都冲破栅栏之后,于是各个线程都依次执行它们后续的操作。
3 CyclicBarrier
与CountDownLatch
的区别
-
CyclicBarrier
底层的计数器是可以通过reset()方法重置以达到循环使用的目的,而CountDownLatch
计数器不可被重置。 -
CyclicBarrier
用于等待其他线程运行到栅栏位置(当所有线程都运行到栅栏位置则冲破栅栏),CountDownLatch
允许一个或多个线程等待一组事件的发生。 - 在
CyclicBarrier
中,所有参与的线程职责是一样的;而CountDownLatch
中参与的线程的职责是不一样,有的在倒计时,有的在等待倒计时结束。