CyclicBarrier和CountDownLatch的区别
CyclicBarrier和CountDownLatch对比
CountDownLatch | CyclicBarrier |
---|---|
减数计数方式 | 加计数方式 |
计算为0时释放所有等待的线程 | 计数到达指定值时释放所有等待线程 |
计数为0时,无法重置 | 技术叨叨指定值时,计数置为0重新开始 |
调用countdown()方法计数减一,调用await()方法只进程阻塞,对计数没有任何影响 | 调用await()方法计数+1,若加1后的值不等于构造方法的值,则线程阻塞 |
不可重复利用 | 可重复利用 |
CountDownLatch
Countdownlatch是一个同步工具类;用来协调多个线程之间的同步;
这个工具通常用来控制线程等待;它可以让某一个线程等待知道倒计时结束,在开始执行;
某一线程在开始运行前等待n个线程执行完毕;将CountDownLatch的计数器初始化为n:new CountDownLatch(n);每当一个任务线程执行完毕,就将计数器减1,CountDownLatch.Countdown;当计数器的值变为0时;在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕;
实现多个线程开始执行任务的最大并行性;注意是并行性;而不是并发性;强调的是多个线程在某一时刻同时执行,类似于赛跑;将多个线程放到起点;等待发令枪响;然后同时开跑;做法是初始化一个共享的CountDownLatch对象;将其计数器初始化为1:new CountdownLatch(1);多个线程在开始执行任务前首先CountDownLatch.await(),当主线程调用countdownl时,计数器变为0;多个线程同时被唤醒;
CountDownLatch实例
有五个人,一个裁判。这五个人同时跑,裁判开始计时,五个人都到终点了,裁判喊停,然后统计这五个人从开始跑到最后一个撞线用了多长时间。
1 | import java.util.concurrent.CountDownLatch; |
CountDownLatch强调的是一个线程(或多个)需要等待另外的n个线程干完某件事情之后才能继续执行。 上述例子,main线程是裁判,5个AWorker是跑步的。运动员先准备,裁判喊跑,运动员才开始跑(这是第一次同步,对应begin)。5个人谁跑到终点了,countdown一下,直到5个人全部到达,裁判喊停(这是第二次同步,对应end),然后算时间。
Countdownlatch的不足
Countdownlatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,他不能再次被使用
CyclicBarrier
CyclicBarrier和CountDownLatch非常类似,他也可以实现线程间的技术等待,但是它的功能比CountDownLatch更加强大和复杂。主要应用场景和CountDownLatch类似
CyclicBarrier的字面意思是可循环使用的屏障,它要做的事情是,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法时CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障。然后当前线程被阻塞;
CyclicBarrier的应用场景
CyclicBarrier可以用于多线程计算数据,最后合并结果的应用场景。比如我们用一个Excel保存了用户所有银行流水,每个Sheet保存每一个账户近一年的每一笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,使用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水;
CyclicBarrier实例
继续,还是这五个人(这五个人真无聊..),这次没裁判。规定五个人只要都跑到终点了,大家可以喝啤酒。但是,只要有一个人没到终点,就不能喝。 这里也没有要求大家要同时起跑(当然也可以,加latch)
1 | import java.util.concurrent.BrokenBarrierException; |
CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。正如上例,只有5个人全部跑到终点,大家才能开喝,否则只能全等着。
CountDownLatch是计数器,只能使用一次,而CyclicBarrier的计数器提供reset功能,可以多次使用
JavaDoc中的定义
CountDownLatch:一个或者多个线程,等待其他线程完成某件事情之后,等待其他多个线程完成某件事情之后才能执行;
CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行;
对于CountDownLatch来说,重点是一个线程(多个线程)等待”,而其他的N个线程在完成”某件事情”之后,可以终止,也可以等待,而对于CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待;CountDownLatch是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而CyclicBarrier更像是一个阀门,需要所有线程都要到达,阀门才能打开,然后继续执行;