CountDownLatch位于java.util.concurrent包下,是JDK1.5的并发包下的新特性。

首先根据Oracle的官方文档看看CountDownLatch的定义:

  1. A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

简单来说,CountDownLatch是一个同步的辅助类,允许一个或多个线程一直等待,直到其它线程完成它们的操作。

这里就涉及两个问题:

1.如何让一个或多个线程一直等待;

2.如何让这些线程知道其它线程已经完成它们的操作

这两个问题主要是使用一个count的属性解决。使用count初始化CountDownLatch,然后需要等待的线程调用await方法。await方法会一直受阻塞直到count=0。

而其它线程完成自己的操作后,调用countDown()使计数器count减1。当count减到0时,所有在等待的线程均会被释放,并且count无法被重置。如果需要重置,请参考CyclicBarrier

假设有以下的场景,3个学生做试卷考试,老师要等所有学生做完试卷后才收卷。具体代码如下:

先看学生Student.java:

  1. 1 import java.util.Random;
  2. 2 import java.util.concurrent.CountDownLatch;
  3. 3 import java.util.concurrent.TimeUnit;
  4. 4
  5. 5 public class Student implements Runnable {
  6. 6
  7. 7 private int num;
  8. 8 private CountDownLatch cdlatch;
  9. 9
  10. 10 Student(int num,CountDownLatch latch){
  11. 11 this.num = num;
  12. 12 this.cdlatch = latch;
  13. 13 }
  14. 14
  15. 15 @Override
  16. 16 public void run() {
  17. 17 doExam();
  18. 18 try {
  19. 19 TimeUnit.SECONDS.sleep(new Random().nextInt(10));
  20. 20 } catch (InterruptedException e) {
  21. 21 // TODO Auto-generated catch block
  22. 22 e.printStackTrace();
  23. 23 }
  24. 24 System.out.println("Student "+num+" finished!");
  25. 25 cdlatch.countDown();
  26. 26 }
  27. 27
  28. 28 private void doExam(){
  29. 29 System.out.println("Student "+num+" is doing the exam!");
  30. 30 }
  31. 31
  32. 32 }

再看老师Teacher.java:

  1. 1 import java.util.concurrent.CountDownLatch;
  2. 2
  3. 3 public class Teacher implements Runnable{
  4. 4
  5. 5 private CountDownLatch cdlatch;
  6. 6
  7. 7 Teacher(CountDownLatch latch){
  8. 8 this.cdlatch = latch;
  9. 9 }
  10. 10
  11. 11 @Override
  12. 12 public void run() {
  13. 13 // TODO Auto-generated method stub
  14. 14 try {
  15. 15 System.out.println("teacher is waiting...");
  16. 16 cdlatch.await();
  17. 17 System.out.println("teacher is collecting......");
  18. 18 } catch (InterruptedException e) {
  19. 19 // TODO Auto-generated catch block
  20. 20 e.printStackTrace();
  21. 21 }
  22. 22 }
  23. 23
  24. 24 }
  1. 1 import java.util.concurrent.CountDownLatch;
  2. 2 import java.util.concurrent.ExecutorService;
  3. 3 import java.util.concurrent.Executors;
  4. 4
  5. 5 public class TestCountDownLatch {
  6. 6
  7. 7 public static void main(String[] args) {
  8. 8
  9. 9 ExecutorService executor = Executors.newCachedThreadPool();
  10. 10
  11. 11 CountDownLatch latch = new CountDownLatch(3);
  12. 12
  13. 13 Student s1 = new Student(101, latch);
  14. 14 Student s2 = new Student(102, latch);
  15. 15 Student s3 = new Student(103, latch);
  16. 16 Teacher t = new Teacher(latch);
  17. 17
  18. 18 executor.execute(t);
  19. 19 executor.execute(s1);
  20. 20 executor.execute(s2);
  21. 21 executor.execute(s3);
  22. 22
  23. 23 executor.shutdown();
  24. 24
  25. 25 }
  26. 26
  27. 27 }

我们可以看到运行的结果:

teacher is waiting...
Student 101 is doing the exam!
Student 102 is doing the exam!
Student 103 is doing the exam!
Student 102 finished!
Student 101 finished!
Student 103 finished!
teacher is collecting......

再来看一个稍微复杂点的例子,10个选手比赛跑步,在枪响后同时起跑,全部到达终点后比赛结束:

  1. 1 import java.util.concurrent.CountDownLatch;
  2. 2 import java.util.concurrent.ExecutorService;
  3. 3 import java.util.concurrent.Executors;
  4. 4
  5. 5
  6. 6 public class CountDownLatchDemo {
  7. 7
  8. 8 private static int PLAYER_NUM = 10;
  9. 9
  10. 10 public static void main(String[] args) {
  11. 11
  12. 12 final CountDownLatch beginSignal = new CountDownLatch(1);
  13. 13 final CountDownLatch endSignal = new CountDownLatch(PLAYER_NUM);
  14. 14
  15. 15 ExecutorService executorService = Executors.newFixedThreadPool(PLAYER_NUM);
  16. 16
  17. 17 for(int i=0;i<PLAYER_NUM;i++){
  18. 18 final int num = i+1;
  19. 19 Runnable runner = new Runnable(){
  20. 20
  21. 21 @Override
  22. 22 public void run() {
  23. 23 // TODO Auto-generated method stub
  24. 24 System.out.println("No. "+num+" is waiting...");
  25. 25 try {
  26. 26 beginSignal.await();
  27. 27 System.out.println("No. "+num+" begin running");
  28. 28 Thread.sleep((long) (Math.random() * 10000));
  29. 29 System.out.println("No." + num + " arrived");
  30. 30 } catch (InterruptedException e) {
  31. 31 // TODO Auto-generated catch block
  32. 32 e.printStackTrace();
  33. 33 }finally{
  34. 34 endSignal.countDown();
  35. 35 }
  36. 36 }
  37. 37
  38. 38 };
  39. 39 executorService.execute(runner);
  40. 40 }
  41. 41
  42. 42 System.out.println("before Game Start");
  43. 43 beginSignal.countDown();
  44. 44 System.out.println("Game Start");
  45. 45 System.out.println("---In the middle of the game---");
  46. 46 try {
  47. 47 endSignal.await();
  48. 48 } catch (InterruptedException e) {
  49. 49 // TODO Auto-generated catch block
  50. 50 e.printStackTrace();
  51. 51 }finally{
  52. 52 System.out.println("Game Over!");
  53. 53 executorService.shutdown();
  54. 54 }
  55. 55
  56. 56 }
  57. 57
  58. 58 }

以上逻辑不难理解,beginSignal的count=0时,runner线程开始运行,直到endSignal的count=0时结束。

接下来分析一下运行6次的结果:

可以看到,因为有beginSignal,所以可以保证所有runner都waiting以后,才begin running。同理,因为有endSignal,可以保证所有runner arrived后才Game Over!

但是,这里的需要留意主线程的几个输出:

  1. 1 System.out.println("before Game Start");
  2. 2 beginSignal.countDown();
  3. 3 System.out.println("Game Start");
  4. 4 System.out.println("---In the middle of the game---");

1.尽管before Game Start在countDown()之前,但不能保证is waiting全部输出完后,才输出before Game Start。

2.“Game Start”和"In the middlel of the game"虽然都在countDown()之后,但在多线程的环境下(主线程也是线程之一),无法预计两个字段输出的位置。从上面的case看,有可能在running的前面,中间和后面,无法预计。这里要十分注意。

3.因为有Thread.sleep,所以arrived都在running之后出现。否则,arrived出现的位置,就不一定都在running之后了。

参考:

http://www.cnblogs.com/shiyanch/archive/2011/04/04/2005233.html

http://blackgu.blogbus.com/logs/69596661.html

CyclicBarrier和CountDownLatch一样,都是关于线程的计数器。

用法略有不同,测试代码如下:

  1. 1 public class TestCyclicBarrier {
  2. 2
  3. 3 private static final int THREAD_NUM = 5;
  4. 4
  5. 5 public static class WorkerThread implements Runnable{
  6. 6
  7. 7 CyclicBarrier barrier;
  8. 8
  9. 9 public WorkerThread(CyclicBarrier b){
  10. 10 this.barrier = b;
  11. 11 }
  12. 12
  13. 13 @Override
  14. 14 public void run() {
  15. 15 // TODO Auto-generated method stub
  16. 16 try{
  17. 17 System.out.println("Worker's waiting");
  18. 18 //线程在这里等待,直到所有线程都到达barrier。
  19. 19 barrier.await();
  20. 20 System.out.println("ID:"+Thread.currentThread().getId()+" Working");
  21. 21 }catch(Exception e){
  22. 22 e.printStackTrace();
  23. 23 }
  24. 24 }
  25. 25
  26. 26 }
  27. 27
  28. 28 /**
  29. 29 * @param args
  30. 30 */
  31. 31 public static void main(String[] args) {
  32. 32 // TODO Auto-generated method stub
  33. 33 CyclicBarrier cb = new CyclicBarrier(THREAD_NUM, new Runnable() {
  34. 34 //当所有线程到达barrier时执行
  35. 35 @Override
  36. 36 public void run() {
  37. 37 // TODO Auto-generated method stub
  38. 38 System.out.println("Inside Barrier");
  39. 39
  40. 40 }
  41. 41 });
  42. 42
  43. 43 for(int i=0;i<THREAD_NUM;i++){
  44. 44 new Thread(new WorkerThread(cb)).start();
  45. 45 }
  46. 46 }
  47. 47
  48. 48 }
  49. 49 /*
  50. 50 以下是输出:
  51. 51 Worker's waiting
  52. 52 Worker's waiting
  53. 53 Worker's waiting
  54. 54 Worker's waiting
  55. 55 Worker's waiting
  56. 56 Inside Barrier
  57. 57 ID:12 Working
  58. 58 ID:8 Working
  59. 59 ID:11 Working
  60. 60 ID:9 Working
  61. 61 ID:10 Working
  62. 62 */
  1. CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。
  2. CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。
  3. CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

CyclicBarrier及CountDownLatch的使用的更多相关文章

  1. CyclicBarrier和CountDownLatch的差别

    CyclicBarrier和CountDownLatch都用多个线程之间的同步,共同点:同时有N个线程在 CyclicBarrier(CountDownLatch) 等待上等待时,CyclicBarr ...

  2. Java并发之CyclicBarrier、CountDownLatch、Phaser

    在Java多线程编程中,经常会需要我们控制并发流程,等其他线程执行完毕,或者分阶段执行.Java在1.5的juc中引入了CountDownLatch和CyclicBarrier,1.7中又引入了Pha ...

  3. 《java.util.concurrent 包源码阅读》21 CyclicBarrier和CountDownLatch

    CyclicBarrier是一个用于线程同步的辅助类,它允许一组线程等待彼此,直到所有线程都到达集合点,然后执行某个设定的任务. 现实中有个很好的例子来形容:几个人约定了某个地方集中,然后一起出发去旅 ...

  4. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  5. JAVA多线程提高十:同步工具CyclicBarrier与CountDownLatch

    今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公 ...

  6. java多线程开发之CyclicBarrier,CountDownLatch

    最近研究了一个别人的源码,其中用到多个线程并行操作一个文件,并且在所有线程全部结束后才进行主线程后面的处理. 其用到java.util.concurrent.CyclicBarrier 这个类. Cy ...

  7. JDK源码分析之concurrent包(四) -- CyclicBarrier与CountDownLatch

    上一篇我们主要通过ExecutorCompletionService与FutureTask类的源码,对Future模型体系的原理做了了解,本篇开始解读concurrent包中的工具类的源码.首先来看两 ...

  8. Android进阶——多线程系列之Semaphore、CyclicBarrier、CountDownLatch

    今天向大家介绍的是多线程开发中的一些辅助类,他们的作用无非就是帮助我们让多个线程按照我们想要的执行顺序来执行.如果我们按照文字来理解Semaphore.CyclicBarrier.CountDownL ...

  9. JAVA多线程学习十三 - 同步工具CyclicBarrier与CountDownLatch

    一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序 ...

随机推荐

  1. Css Position定位(简易版本)

    准备前的知识: 定位只对块级起作用.如div,p等元素是块级元素,如果是内联元素则可以先变成块级元素,display:block即可. 开始讲解: 定位共四种:static,fixed,relativ ...

  2. 天啦噜!原来Chrome自带的开发者工具还能这么用!

    作者:余博伦链接:https://zhuanlan.zhihu.com/p/22665710来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. Chrome自带开发者工具. ...

  3. 仿照jquery封装一个自己的js库

    所谓造轮子的好处就是复习知识点,加深对原版jquery的理解.本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现.主要涉及知识点包括 ...

  4. CheckedListBoxControl 或CheckedListBox 控件中显示水平滚动条 z

    public partial class Form1 : Form { public Form1() { InitializeComponent(); DisplayHScroll(); } /// ...

  5. linux下命令行的查找顺序

    由下可知,linux通过$PATH的路径顺序,由左至由依次查找某个程序,如果有两个路径下都有这个程序,以先找到的为准 [rpc_server]$ which 23/usr/bin/which: no ...

  6. sh_Spring整合Hibernate

    分别介绍了Sping和Hibernate,以下是将它们整合到一块去了.   一.Hibernate内容 1.创建PO类. package cn.tgb.domain; //User实体 public ...

  7. 以goroutine为例看协程的相关概念

    转自  http://wangzhezhe.github.io/blog/2016/02/17/golang-scheduler/ 基本上是网上相关文章的梳理,初衷主要是想了解下golang中的gor ...

  8. golang map to struct

    http://stackoverflow.com/questions/26744873/converting-map-to-struct func SetField(obj interface{}, ...

  9. Python web 框架:web.py

    web.py 是一个Python 的web 框架,它简单而且功能强大.web.py 是公开的,无论用于什么用途都是没有限 制的. web.py 安装: pip install web.py 下面开始我 ...

  10. PCB常用单位转换 mil 英尺

    PCB常用单位转换 mil 英尺 相关常用单位     1mil   = 0.0254mm 100mil = 2.54mm 1英寸   = 1000mil = 2.54cm 1英尺   = 12英寸  ...