携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
简介
CyclicBarrier 简称循环栅栏,也是一个同步辅助类,允许一组线程相互等待,直到到达某个公共的屏障点,通过它可以完成多个线程之间相互等待,只有当每个线程都准备就绪后,才能各自继续执行后面的操作。
说明:CyclicBarrier作用是让一组线程相互等待,当达到一个共同点时,所有之前等待的线程再继续执行,且CyclicBarrier 功能可重复使用。
常见示例
- 校运会期间,举行的跑步项目,只有当10个运动员全部就位时,裁判才开始通知跑步。
- 过年做长途汽车回家,由于中途不允许上、下车运营公司为了收益最大化,通常会等人坐满了车开始发车
- .......
基本使用
public class CyclicBarrierTest
{
private static Logger logger =LoggerFactory.getLogger(CountDownLatchTest.class);
public static void main(String[] args)
{
//执行
run();
}
public static void run()
{
CyclicBarrier cyclicBarrier =new CyclicBarrier(10, ()->{
logger.info("运动员已全部就绪,准备开始起跑");
});
for(int i=1;i<=10;i++){
new Thread(()->{
logger.info(Thread.currentThread().getName()+":运动员已就位");
try
{
//等待
cyclicBarrier.await();
}
catch (Exception e)
{
logger.info("invoke service error:{}",e);
}
}).start();
}
}
}
执行结果:
原理
CyclicBrrier是通过独占锁ReentrantLock来实现计数器的原子性更新的,其中await的具体实现方法如下:
CyclicBarrier和CountDownLatch 区别
虽然CyclicBarrier和CountDownLatch的功能非常相似,但是还是存在相关区别具体如下:
-
CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法进行重置,并且可以循环使用.
-
CountDownLatch主要实现1个或n个线程需要等待其他线程完成某项操作之后,才能继续往下执行,描述的是1个或n个线程等待其他线程的关系。而CyclicBarrier主要实现了多个线程之间相互等待,直到所有的线程都满足了条件之后,才能继续执行后续的操作,描述的是各个线程内部相互等待的关系。
-
CyclicBarrier能够处理更复杂的场景,如果计算发生错误,可以重置计数器让线程重新执行一次。
-
CyclicBarrier中提供了很多有用的方法,比如:可以通过getNumberWaiting()方法获取阻塞的线程数量,通过isBroken()方法判断阻塞的线程是否被中断。
总结
本文对CyclicBrrier进行讲解,CyclicBrrier是通过独占锁ReentrantLock来实现计数器的原子性更新的,CyclicBrrier的await()方法,会使计数器-1,并判断当前的计数器是否为 0,如果不为0就会阻塞等待,并计时器为 0之后,才能继续执行剩余任务。如有疑问,请随时反馈。