Java多线程/并发24、Countdownlatch应用以及与CyclicBarrier的区别
2017-05-07 15:17
507 查看
Countdownlatch应用
有时候会有这样的需求:多个线程同时工作,其中几个可以随意的并发执行,但有一个线程需要等其他线程工作结束后,才能运行。举个例子,我们知道的迅雷下载,会同时开启多个线程分块下载一个大文件,每个线程下载固定的一段,最后由另外一个线程校验并拼接这些分段。这种场景可使用CountDownLatch来控制并发的执行顺序。Countdownlatch 是一个倒计数器锁。调用CountDownLatch对象的await()方法使线程处于等待状态,调用countDown()方法的线程会将计数器减1,当计数到达0时,所有等待线程(可多个,但通常的应用场景中只有一个等待者)开始继续执行。
这里还是用F1举例:
F1赛车每次进站后,车队技师都需要在尽可能短的时间内对赛车做三个工作:加注燃油、更换轮胎、更换刹车片。当然,这三项工作都是同时进行的。只有当这三项工作完成,赛车才能驶出维修站。
public class CountdownlatchDemo { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { CountDownLatch cDownLatch=new CountDownLatch(3);//初始计数器值为3,对应3个维修组 /*1、赛车进站*/ System.out.println("F1赛车进站,时间:"+Calendar.getInstance().get(Calendar.SECOND)); /*2、三个维修组同时开始对赛车维护*/ List<mechanician> mechanician_team=new ArrayList<mechanician>(); mechanician_team.add(new mechanician("加注燃油", cDownLatch)); mechanician_team.add(new mechanician("更换轮胎", cDownLatch)); mechanician_team.add(new mechanician("更换刹车片", cDownLatch)); for(mechanician mec:mechanician_team){ new Thread(mec).start(); } /*3、等待技师完成三项工作。实际就是等待cDownLatch计数器变成0*/ cDownLatch.await(); /*4、完成维护,出发*/ System.out.println("F1赛车维修完毕,出发!时间:"+Calendar.getInstance().get(Calendar.SECOND)); } /*维修技师类*/ static class mechanician implements Runnable{ String work; CountDownLatch cDownLatch; public mechanician(String work,CountDownLatch cDownLatch) { this.work = work; this.cDownLatch = cDownLatch; } @Override public void run() { try { int random=new Random().nextInt(7); TimeUnit.SECONDS.sleep(random); System.out.println(Thread.currentThread().getName()+"--- "+work+" 完成,此组耗时:"+random+"秒"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ /*当前技师的任务完成,cDownLatch计算器减1 *通常countDown放在finally里中使用*/ cDownLatch.countDown(); } } } }
运行输出:
F1赛车进站,时间:37 Thread-1--- 更换轮胎 完成,此组耗时:4秒 Thread-2--- 更换刹车片 完成,此组耗时:4秒 Thread-0--- 加注燃油 完成,此组耗时:5秒 F1赛车维修完毕,出发!时间:42
可以看到,赛车会等待所有工作完成后再出发。
如果删除 cDownLatch.await();会怎么样呢?结果是顺序乱了,赛车并没有待机械维修组完成工作就跑了。
F1赛车进站,时间:18 F1赛车维修完毕,出发!时间:18 Thread-1--- 更换轮胎 完成,此组耗时:5秒 Thread-2--- 更换刹车片 完成,此组耗时:6秒 Thread-0--- 加注燃油 完成,此组耗时:6秒
最后聊一下CountDownLatch和CyclicBarrier的区别
虽然两者在大部分情况下,可以代替使用,但他们是有区别的:CyclicBarrier可以循环使用,而CountDownLatch只能用一次。但这并不是最主要的区别,也并不是设计这两个类的初衷。
它们主要是为了不同应用场景而设计出来的:
CountDownLatch应用场景:主/从任务模式。是 一个或多个线程(主任务), 等待另外N个线程(从任务)完成某个事情之后才能执行。
CyclicBarrier应用场景:队友模式。一组N个线程(N个队友)相互等待,任意一个线程(某个队友)没有完成任务,所有线程都等着。直到这一组所有线程的任务完成,这组中每个线程才能继续往下运行。
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个或多个线程(主任务)”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是N个线程,他们之间任何一个没有完成,所有的线程都必须等待。
相关文章推荐
- 并发工具类CountDownLatch与CyclicBarrier的区别
- CountDownLatch、CyclicBarrier、Semaphore共同之处与区别以及各自使用场景
- countDownLatch 与 CyclicBarrier 区别
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程之2——同步工具类的使用(CountDownLatch,CyclicBarrier,BlockungQueue,Semaphore)
- 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)
- Java并发编程深入学习——CountDownLatch、CyclicBarrier和Semaphore
- AbstractQueuedSynchronizer在工具类ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier中的应用
- java并发编程——八 理解分析并发组件-CountDownLatch\CyclicBarrier\Exchanger\Semaphore
- 《Java 7 并发编程指南》学习概要 (3)Semaphore, CountDownLatch, CyclicBarrier , Phaser, Exchanger
- java并发之CountDownLatch、Semaphore和CyclicBarrier
- Java并发:同步工具类详解(CountDownLatch、CyclicBarrier、Semaphore)
- java高并发之CountDownLatch,CyclicBarrier和join
- Java并发之CyclicBarrier、CountDownLatch、Phaser
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- AbstractQueuedSynchronizer在工具类Semaphore、CountDownLatch、ReentrantLock中的应用和CyclicBarrier
- Java并发之CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore