JUC系列(三)-工具类之CyclicBarrier

53 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

简介

CyclicBarrier 简称循环栅栏,也是一个同步辅助类,允许一组线程相互等待,直到到达某个公共的屏障点,通过它可以完成多个线程之间相互等待,只有当每个线程都准备就绪后,才能各自继续执行后面的操作。

图片.png

说明: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();
         }
    }
}

执行结果:

图片.png

原理

CyclicBrrier是通过独占锁ReentrantLock来实现计数器的原子性更新的,其中await的具体实现方法如下:

图片.png

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之后,才能继续执行剩余任务。如有疑问,请随时反馈。