CountDownLatch的概念
CountDownLatch的作用很简单,就是一个或者一组线程在开始执行操作之前,必须要等到其他线程执行完才可以。例如等待学生考完收卷的老师。
源码分析
核心成员变量
是一个基于AQS实现的同步器
Sync对AQS的重写
其中同步器的state承接CountDownLatch的计数count
tryAcquireShared
可见计数count是0,就返回1
tryReleaseShared
可见是在做倒数操作
构造函数
构造同步器sync
await()、await(timeout, TimeUnit) - 等待方法
await方法调用的就是同步器的acquire方法
回顾下,就是调用tryAcquireShared,上面看到了具体实现,那么小于0的条件是:计数器count != 0,业务含义就是还有任务没有处理完,要等待
这个时候,执行await的线程(一般是主线程)就会进同步队列里面等着去
除非使用带时间的await方法,到期会重新自旋获取锁
countDown() - 计数方法
countdown方法调用的就是释放锁方法,每次使计数减1
使用的时候,默认每个分配任务的子线程持有一把锁,子线程调用countDown后,归还一把,指导计数count变成0,使用await阻塞的线程就可以拿到锁走下去
countDownLatch使用案例
CountDownLatch典型用法:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。
一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
CountDownLatch的问题
CountDownLatch是一次性的 , 计数器的值只能在构造方法中初始化一次 , 之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后 , 它不能再次被使用。因此这个方法比较适合用于程序启动时一次性加载配置。
CountDown的子线程如果抛异常很可能走不到countDown环节,await的线程就有可能永远被阻塞,存在风险。这里注意使用try-finally逻辑让countDown()方法总能被调用。
评论区