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

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

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

再看老师Teacher.java:

 1 import java.util.concurrent.CountDownLatch;
 2
 3 public class Teacher implements Runnable{  4  5 private CountDownLatch cdlatch;  6  7  Teacher(CountDownLatch latch){  8 this.cdlatch = latch;  9  } 10 11  @Override 12 public void run() { 13 // TODO Auto-generated method stub 14 try { 15 System.out.println("teacher is waiting..."); 16  cdlatch.await(); 17 System.out.println("teacher is collecting......"); 18 } catch (InterruptedException e) { 19 // TODO Auto-generated catch block 20  e.printStackTrace(); 21  } 22  } 23 24 }

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

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

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

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

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

1 System.out.println("before Game Start");
2 beginSignal.countDown();
3 System.out.println("Game Start"); 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 public class TestCyclicBarrier {
 2
 3 private static final int THREAD_NUM = 5;  4  5 public static class WorkerThread implements Runnable{  6  7  CyclicBarrier barrier;  8  9 public WorkerThread(CyclicBarrier b){ 10 this.barrier = b; 11  } 12 13  @Override 14 public void run() { 15 // TODO Auto-generated method stub 16 try{ 17 System.out.println("Worker's waiting"); 18 //线程在这里等待,直到所有线程都到达barrier。 19  barrier.await(); 20 System.out.println("ID:"+Thread.currentThread().getId()+" Working"); 21 }catch(Exception e){ 22  e.printStackTrace(); 23  } 24  } 25 26  } 27 28 /** 29  * @param args 30 */ 31 public static void main(String[] args) { 32 // TODO Auto-generated method stub 33 CyclicBarrier cb = new CyclicBarrier(THREAD_NUM, new Runnable() { 34 //当所有线程到达barrier时执行 35  @Override 36 public void run() { 37 // TODO Auto-generated method stub 38 System.out.println("Inside Barrier"); 39 40  } 41  }); 42 43 for(int i=0;i<THREAD_NUM;i++){ 44 new Thread(new WorkerThread(cb)).start(); 45  } 46  } 47 48 } 49 /* 50 以下是输出: 51 Worker's waiting 52 Worker's waiting 53 Worker's waiting 54 Worker's waiting 55 Worker's waiting 56 Inside Barrier 57 ID:12 Working 58 ID:8 Working 59 ID:11 Working 60 ID:9 Working 61 ID:10 Working 62 */

  1. CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。
  2. CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。
  3. CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

转载于:https://www.cnblogs.com/jianwei-dai/p/6269771.html

CyclicBarrier及CountDownLatch的使用相关推荐

  1. CyclicBarrier和CountDownLatch区别

    这两天写多线程时,用到了CyclicBarrier,下意识的认为CyclicBarrier和CountDownLatch作用很像,就翻阅资料查了一下,说一下他们的区别吧 CyclicBarrier和C ...

  2. 请简要说明一下CyclicBarrier和CountDownLatch的区别?

    请简要说明一下CyclicBarrier和CountDownLatch的区别? CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们的侧重点不同: ①Count ...

  3. CyclicBarrier 和CountDownLatch使用详解

    http://xijunhu.iteye.com/blog/713433 http://www.blogjava.net/jlins-you/archive/2012/04/24/376516.htm ...

  4. Java多线程学习三十五: CyclicBarrier 和 CountDownLatch 有什么不同

    CyclicBarrier 和 CountDownLatch 有什么不同? CyclicBarrier作用 CyclicBarrier 和 CountDownLatch 确实有一定的相似性,它们都能阻 ...

  5. Java并发编程之CyclicBarrier和CountDownLatch

    1.CyclicBarrier简介 CyclicBarrier(栅栏):拦截一组线程并使其阻塞,直到其内部的计数器归零,再唤醒所有的阻塞线程继续执行任务. 基础属性 public class Cycl ...

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

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

  7. 16_张孝祥_多线程_同步工具CyclicBarrier与CountDownLatch

    转载: CyclicBarrier的用法 CountDownLatch(倒计时计数器)使用说明 参考: CyclicBarrier和CountDownLatch区别 CyclicBarrier Cyc ...

  8. CyclicBarrier和CountDownLatch使用上的区别

    2018.12.12更新 在学习了CyclicBarrier之后发现,CyclicBarrier也可以实现跟CountDownLatch类似的功能,只需要在它的parties中多设置一个数,将主线程加 ...

  9. CyclicBarrier和CountDownLatch的用法与区别

    前言 CyclicBarrier和CountDownLatch这两个工具都是在java.util.concurrent包下,并且平时很多场景都会使用到. 本文将会对两者进行分析,记录他们的用法和区别. ...

最新文章

  1. 影响和改变世界的50件发明专利,猜下中国有几个?
  2. CI类实现session基本用法
  3. JAVA虚拟机内存不够解决办法
  4. 【源码阅读】dbutil包中BasicRowProcessor内部类CaseInsensiti...
  5. document.body、document.documentElement和window获取视窗大小的区别
  6. Spring Security 入门(1-4-1)Spring Security - 认证过程
  7. html数学公式标记,在网页中显示数学公式
  8. 卡巴斯基7.0离线更新升级包病毒库
  9. 解二元一次方程组的c语言编程,如何利用C语言求二元一次方程的解
  10. 服务器显示共享文件夹的图标,Win7共享文件夹上的小锁图标怎么关闭?
  11. CSS W3C 统一验证工具和压缩
  12. Locks Aren't Slow; Lock Contention Is
  13. R语言报错:Error in data[[rowvar]] : attempt to select less than one element in get1index
  14. zabbix3.0 之短信报警配置
  15. 听说今年金三银四变成金一银二了。
  16. Android Studio实现简单计算器
  17. 《大数据可视化》课后习题答案-何光威版
  18. 【粉丝福利,限时免费】【千里之行,始于脚下】我在CSDN上的精品博文汇总,收藏起来慢慢看
  19. 2019-详细Android Studio开发百度地图(4)—百度地图_路线规划的实现
  20. UDA:Unsupervised Data Augmentation for Consistency Training

热门文章

  1. python中的构造函数和构造函数和析构函数的作用
  2. linux 查看各目录(文件夹)下文件大小
  3. 论 ACM 与泡妞 (转载)
  4. Docker+Jenkins+Gitlab+Django应用部署实践
  5. 网站的domain不在首页的原因
  6. gulp-babel 阻止了js文件编译的进程?
  7. C#编程(三十五)----------foreach和yield
  8. 让Qt Creator支持Windows Phone 8开发
  9. weblogic服务器启动报错
  10. iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客