文章目录
一、CyclicBarrier是什么?它的作用是什么?
CyclicBarrier也是JUC包为处理多线程情况下的某些场景所创建的一个工具类。一般都将其译为:循环栅栏。它主要的功能是对多个线程进行阻塞,直至满足栅栏设定的阈值,才会对阻塞的所有线程进行唤醒放行操作。当然循环也是一个很重要的部分,它其实就是下一批线程同样需要达到相同的条件才会放行,这样就达到了循环拦截的作用。
二、CyclicBarrier的实现原理是什么?
它是通过ReentrantLock和Condition来实现的,主要涉及了 下面三个部分:
- 1、准备阶段:将所有未满足条件的线程放入条件队列,并阻塞对应线程;
- 2、过度阶段:当条件满足(线程数量达到阈值)时,会将条件队列中的所有线程全部出队,将其一一放入同步等待队列中,并且在当前线程执行完成后,会唤醒同步同步等待队列头节点的后续节点线程;
- 3、完成阶段:被唤醒的线程尝试获取锁,如果获取成功则执行任务,如果未获取成功则继续阻塞在同步队列中。当被唤醒的线程执行完任务后会继续唤醒下一节点的线程,直至同步队列中所有的节点线程全部执行完毕后,重复上诉所有流程
三、CyclicBarrier和CountDownLatch有什么区别?
- 1、CountDownLatch是基于AQS中的共享锁来实现的功能,而CyclicBarrier是通过ReentrantLock加Condition来实现的;
- 2、CountDownLatch的阻塞只有一次效果,当一批线程被阻塞过后,下一批线程再次通过的时候就不会阻塞了,而CyclicBarrier能达到循环阻塞的效果,每次都只允许阈值的线程数量通过;
- 3、CountDownLatch的使用更加复杂,它需要countDown()和await()方法连用,而CyclicBarrier只需要使用await()方法就能实现功能了;
注意:CountDownLatch是使用的AQS共享锁中的await()方法,而CyclicBarrier使用的是Condition中的await方法
四、CyclicBarrier的简单实现
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "开始等待其他线程。。。");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "开始执行任务。。。");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + "任务执行完毕。。。");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
});
thread.start();
}
结果如下:
之所以选择3和5两个参数,是为了更好的显示:任务都是那些进入条件队列的线程执行的,而不是阻塞队列执行的。
注意:上述代码为执行完成,还有两个线程处于阻塞状态。所以使用循环栅栏的时候,需要注意运行的线程必须是栅栏设定允许通过数量的整数倍,否则永远会有几个线程处于阻塞状态