CountDownLatch 和CyclicBarrier

本文介绍了并发编程中用于解决同步问题的两种工具:CountDownLatch和CyclicBarrier。通过实现一个模拟项目开发流程的例子,展示了CountDownLatch如何确保任务在所有模块完成后才继续进行。同时,通过一个基于CyclicBarrier的接力赛模拟,说明了它如何让一组线程在共同的障碍点等待并重用这个屏障。文章提供了完整的Java代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来自:http://www.iteye.com/topic/657295多谢作者完美的例子。解决了我的问题!!!

CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数初始化 CountDownLatch。由于调用了 countDown()
方法,所以在当前计数到达零之前,await
方法会一直受阻塞。之后,会释放所有等待的线程,await
的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。

CountDownLatch 很适合用来将一个任务分为n个独立的部分,等这些部分都完成后继续接下来的任务,CountDownLatch 只能出发一次,计数值不能被重置。

CyclicBarrier:

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。

CyclicBarrier可以多次重复使用

下面是两个例子,一个为基于CountDownLatch 的模拟项目,一个项目可以分为多个模块,只有但这些模块都完成后才可以继续下一步的工作。

一个为基于CyclicBarrier的接力赛模拟,有四个队员,当跑完后报出最终成绩。

Java代码 收藏代码
  1. packagecom.woxiaoe.study.thread;
  2. importjava.util.Random;
  3. importjava.util.concurrent.CountDownLatch;
  4. importjava.util.concurrent.ExecutorService;
  5. importjava.util.concurrent.Executors;
  6. importjava.util.concurrent.TimeUnit;
  7. /**
  8. *模拟项目的开发,只有当每个模块都完成后,项目才完成
  9. *每个模块的用时不同
  10. *@author小e
  11. *
  12. *2010-4-30下午07:41:37
  13. */
  14. classModuleimplementsRunnable{
  15. privateCountDownLatchlatch;
  16. privateStringmoduleName;
  17. privateinttime;//用时
  18. publicModule(CountDownLatchlatch,StringmoduleName,inttime){
  19. super();
  20. this.latch=latch;
  21. this.moduleName=moduleName;
  22. this.time=time;
  23. }
  24. @Override
  25. publicvoidrun(){
  26. try{
  27. work();
  28. latch.countDown();
  29. }catch(InterruptedExceptione){
  30. //TODOAuto-generatedcatchblock
  31. e.printStackTrace();
  32. }
  33. }
  34. privatevoidwork()throwsInterruptedException{
  35. TimeUnit.MILLISECONDS.sleep(time);
  36. System.out.println(moduleName+"完成,耗时:"+time);
  37. }
  38. }
  39. classControllerimplementsRunnable{
  40. privateCountDownLatchlatch;
  41. publicController(CountDownLatchlatch){
  42. super();
  43. this.latch=latch;
  44. }
  45. @Override
  46. publicvoidrun(){
  47. try{
  48. latch.await();
  49. System.out.println("所有模块都完成,任务完成");
  50. }catch(InterruptedExceptione){
  51. //TODOAuto-generatedcatchblock
  52. e.printStackTrace();
  53. }
  54. }
  55. }
  56. publicclassProject{
  57. staticfinalintSIZE=20;
  58. publicstaticvoidmain(String[]args){
  59. CountDownLatchlatch=newCountDownLatch(SIZE);
  60. Randomr=newRandom();
  61. ExecutorServiceexec=Executors.newCachedThreadPool();
  62. Controllercontroller=newController(latch);
  63. exec.execute(controller);
  64. for(inti=0;i<SIZE;i++){
  65. exec.execute(newModule(latch,"模块"+(i+1),r.nextInt(2000)));
  66. }
  67. exec.shutdown();
  68. }
  69. }

Output:

模块4 完成,耗时:108模块10 完成,耗时:123模块7 完成,耗时:136模块19 完成,耗时:235模块5 完成,耗时:475模块11 完成,耗时:653模块1 完成,耗时:745模块2 完成,耗时:826模块20 完成,耗时:1030模块16 完成,耗时:1151模块3 完成,耗时:1204模块15 完成,耗时:1219模块13 完成,耗时:1274模块17 完成,耗时:1337模块8 完成,耗时:1366模块6 完成,耗时:1491模块14 完成,耗时:1739模块18 完成,耗时:1766模块12 完成,耗时:1883模块9 完成,耗时:1951所有模块都完成,任务完成


Java代码 收藏代码
  1. packagecom.woxiaoe.study.thread;
  2. importjava.util.Random;
  3. importjava.util.concurrent.CyclicBarrier;
  4. importjava.util.concurrent.ExecutorService;
  5. importjava.util.concurrent.Executors;
  6. importjava.util.concurrent.TimeUnit;
  7. /**
  8. *用java模拟4X100接力赛
  9. *当结束后报成绩,应用CyclicBarrier
  10. *@author小e
  11. *
  12. *2010-4-30下午08:13:40
  13. */
  14. classPlayerimplementsRunnable{
  15. privateStringname;
  16. privateCyclicBarrierbarrier;
  17. privatePlayernext;//下一棒
  18. privateinttime;//用时
  19. privatebooleanrun;//第一棒
  20. publicPlayer(Stringname,CyclicBarrierbarrier,booleanrun){
  21. super();
  22. this.name=name;
  23. this.barrier=barrier;
  24. this.run=run;
  25. }
  26. @Override
  27. publicvoidrun(){
  28. try{
  29. synchronized(this){
  30. while(!run){//等待队员
  31. wait();
  32. }
  33. }
  34. Randomr=newRandom();
  35. TimeUnit.MILLISECONDS.sleep(r.nextInt(2000));
  36. next(next,11+r.nextInt(2));
  37. }catch(InterruptedExceptione){
  38. e.printStackTrace();
  39. }
  40. }
  41. privatevoidnext(Playernext,inttime){
  42. System.out.println(name+"用时:"+time+",交接棒");
  43. if(next!=null){
  44. next.setTime(this.time+time);
  45. synchronized(next){
  46. next.setRun(true);
  47. next.notify();
  48. }
  49. }else{
  50. System.out.println("跑完,总用时:"+(this.time+time));
  51. }
  52. }
  53. publicvoidsetTime(inttime){
  54. this.time=time;
  55. }
  56. publicintgetTime(){
  57. returnthis.time;
  58. }
  59. publicvoidsetNext(Playernext){
  60. this.next=next;
  61. }
  62. publicvoidsetRun(booleanrun){
  63. this.run=run;
  64. }
  65. }
  66. publicclassRelayRace{
  67. publicstaticvoidmain(String[]args)throwsInterruptedException{
  68. finalPlayer[]players=newPlayer[4];
  69. ExecutorServiceexec=Executors.newCachedThreadPool();
  70. CyclicBarrierbarrier=newCyclicBarrier(4,newRunnable(){
  71. @Override
  72. publicvoidrun(){
  73. System.out.println("结束,总用时:"+players[3].getTime());
  74. }
  75. });
  76. for(inti=0;i<4;i++){
  77. players[i]=newPlayer("队员"+(i+1),barrier,i==0);
  78. }
  79. for(inti=0;i<4;i++){
  80. if(i<3){
  81. players[i].setNext(players[i+1]);
  82. exec.execute(players[i]);
  83. }else{
  84. exec.execute(players[3]);
  85. break;
  86. }
  87. }
  88. /*TimeUnit.SECONDS.sleep(3);
  89. *CyclicBarrier可以重用
  90. for(inti=0;i<4;i++){
  91. if(i<3){
  92. players[i].setNext(players[i+1]);
  93. exec.execute(players[i]);
  94. }else{
  95. exec.execute(players[3]);
  96. break;
  97. }
  98. }*/
  99. }
  100. }
Output:
队员1 用时:11,交接棒队员2 用时:11,交接棒队员3 用时:11,交接棒队员4 用时:12,交接棒跑完,总用时:45
来自:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值