CountDownLatch和CyclicBarrier的应用场
网上有很多文章都讨论了CountDownLatch和CyclicBarrier的应用场景,但是大部分CyclicBarrier的应用场景都跟实际情况相去甚远。
先来看看CountDownLatch:
CountDown 的意思是 倒计时,Latch 的意思是 门闩 。
JDK 释中是这样描述的:
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
- 让一个或多个线程持续等待,直到其他多线程执行的一组操作全部完成以后,这些等待的线程才会继续执行。
CountDownLatch的使用场景:
1. 让单个线程等待多个线程
例如:一个服务需要从3个远程接口获取数据,就可以开三个线程并调用远程接口,等待所有远程接口数据返回之后,服务线程再继续执行。
在比如:并发计算,汇总结果。
2. 让多个线程等待
例如:模拟秒杀场景,让一组线程同时等待,同时恢复执行,实现最大程度的并行性。
注意:当高并发请求时,countdownlatch的await方法有可能会引起死锁。
如果线程池中线程的数量较少,在高并发时会出现多个请求占用了全部的线程,但是每个请求又需要await其他线程,被等待的线程拿不到线程资源无法执行,导致多个请求同时进入线程阻塞,最后形成死锁。
解决方法:使用自定义线程池,扩大线程数量,并且建立线程池拒绝机制。
再来看看 CyclicBarrier
Cyclic 的意思是 循环 ,Barrier 的意思是 屏障 。
JDK 注释中是这样描述的:
A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other.
The barrier is called cyclic because it can be re-used after the waiting threads are released.
- CyclicBarrier 是一个同步辅助类,它允许一组线程相互等待直到所有线程都到达一个公共的屏障点。
- 在程序中有固定数量的线程,这些线程有时候必须等待彼此,这种情况下,使用 CyclicBarrier 很有帮助。
- 这个屏障之所以用循环修饰,是因为在所有的线程释放彼此之后,这个屏障是可以重新使用的。
CyclicBarrier的应用场景:
生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是餐厅规定必须等到所有人到齐之后才会上菜。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。
- 这样的例子有助于理解CyclicBarrier,但我相信开发中一定不会遇到这样的场景。
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如现在需要计算10个人12个月的工资,可以开10个worker线程,分别计算每个人的工资,最后,再用barrierAction将这些线程的计算结果进行整合,得出最后结果。
- barrierAction不需要在主线程中执行,这是CyclicBarrier的优势,但是其代价是阻塞了所有的worker线程。
- worker线程计算完成之后,把结果保存就可以释放线程了,用了CyclicBarrier把线程都阻塞了,然后统一释放,这是什么设计?
CyclicBarrier强调线程之间相互等待
受经验所限,在实际开发中,我还没有需要需要线程相互等待的例子,而且这样的场景特别容易造成死锁。
CyclicBarrier强调循环
多轮并行计算:如果需要计算N组人一年的平均工资,每组需要多个线程并行计算,计算完一组,再开始下一组,这样就需要多轮并行计算。CyclicBarrier 比 CountDownLatch 更适合这样的场景。
CountDownLatch与CyclicBarrier的区别:
- CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置
- CyclicBarrier能处理更为复杂的业务场景,比如计算发生错误,可以结束阻塞,重置计数器,重新执行程序
- CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法
- CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程