在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决?

如果是一个线程等待一个线程,则可以通过await()和notify()来实现;

如果是一个线程等待多个线程,则就可以使用CountDownLatch和CyclicBarrier来实现比较好的控制。

下面来详细描述下CountDownLatch的应用场景:

例如:百米赛跑:8名运动员同时起跑,由于速度的快慢,肯定有会出现先到终点和晚到终点的情况,而终点有个统计成绩的仪器,当所有选手到达终点时,它会统计所有人的成绩并进行排序,然后把结果发送到汇报成绩的系统。

其实这就是一个CountDownLatch的应用场景:一个线程或多个线程等待其他线程运行达到某一目标后进行自己的下一步工作,而被等待的“其他线程”达到这个目标后继续自己下面的任务。

这个场景中:

1. 被等待的“其他线程”------>8名运动员

2. 等待“其他线程”的这个线程------>终点统计成绩的仪器

那么,如何来通过CountDownLatch来实现上述场景的线程控制和调度呢?

jdk中CountDownLatch类有一个常用的构造方法:CountDownLatch(int count);

                        两个常用的方法:await()和countdown() 

其 中count是一个计数器中的初始化数字,比如初始化的数字是2,当一个线程里调用了countdown(),则这个计数器就减一,当线程调用了 await(),则这个线程就等待这个计数器变为0,当这个计数器变为0时,这个线程继续自己下面的工作。下面是上述CountDownLatch场景的 实现:

Work类(运动员):

import Java.util.concurrent.CountDownLatch;

public class Work implements Runnable {
 private int id;
 private CountDownLatch beginSignal;
 private CountDownLatch endSignal;
 
 public Work(int id, CountDownLatch begin, CountDownLatch end) {
  this.id = id;
  this.beginSignal = begin;
  this.endSignal = end;
 }

@Override
 public void run() {
  try {
   beginSignal.await();
   System.out.println("起跑...");
   System.out.println("work" + id + "到达终点");
   endSignal.countDown();
   System.out.println("work" + id + "继续干其他事情");
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Main类(终点统计仪器):

import java.util.concurrent.CountDownLatch;

public class Main {
 
 public static void main(String[] args) {
  CountDownLatch begSignal = new CountDownLatch(1);
  CountDownLatch endSignal = new CountDownLatch(8);
  
  for (int i = 0; i < 8; i++) {
   new Thread(new Work(i, begSignal, endSignal)).start();
  }
  
  try {
   begSignal.countDown();  //统一起跑
   endSignal.await();      //等待运动员到达终点
   System.out.println("结果发送到汇报成绩的系统");
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

下面详细描述下CyclicBarrier的应用场景:

有四个游戏玩家玩游戏,游戏有三个关卡,每个关卡必须要所有玩家都到达后才能允许通关。

其 实这个场景里的玩家中如果有玩家A先到了关卡1,他必须等待其他所有玩家都到达关卡1时才能通过,也就是说线程之间需要互相等待,这和 CountDownLatch的应用场景有区别,CountDownLatch里的线程是到了运行的目标后继续干自己的其他事情,而这里的线程需要等待其 他线程后才能继续完成下面的工作。

jdk中CyclicBarrier类有两个常用的构造方法:

1. CyclicBarrier(int parties)

这里的parties也是一个计数器,例如,初始化时parties里的计数是3,于是拥有该CyclicBarrier对象的线程当parties的计数为3时就唤醒,注:这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加1,一直加到初始的值

2. CyclicBarrier(int parties, Runnable barrierAction)

这里的parties与上一个构造方法的解释是一样的,这里需要解释的是第二个入参(Runnable barrierAction),这个参数是一个实现Runnable接口的类的对象,也就是说当parties加到初始值时就出发barrierAction的内容。

下面来实现上述的应用场景:

Player类(玩家类)

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class Player implements Runnable {
  4. private CyclicBarrier cyclicBarrier;
  5. private int id;
  6. public Player(int id, CyclicBarrier cyclicBarrier) {
  7. this.cyclicBarrier = cyclicBarrier;
  8. this.id = id;
  9. }
  10. @Override
  11. public void run() {
  12. try {
  13. System.out.println("玩家" + id + "正在玩第一关...");
  14. cyclicBarrier.await();
  15. System.out.println("玩家" + id + "进入第二关...");
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. } catch (BrokenBarrierException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

GameBarrier类(关卡类,这里控制玩家必须全部到达第一关结束的关口才能进入第二关)

import java.util.concurrent.CyclicBarrier;

public class GameBarrier {
 
 public static void main(String[] args) {
  CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
   
   @Override
   public void run() {
    System.out.println("所有玩家进入第二关!");
   }
  });
  
  for (int i = 0; i < 4; i++) {
   new Thread(new Player(i, cyclicBarrier)).start();
  }
 }
}

java并发编程中CountDownLatch和CyclicBarrier的使用的更多相关文章

  1. Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

  2. 14、Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

  3. 【转】Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore   Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在j ...

  4. Java并发编程:CountDownLatch、CyclicBarrier和Semaphore (总结)

    下面对上面说的三个辅助类进行一个总结: 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待 ...

  5. Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

    原文出处: 海子 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅 ...

  6. Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore[转]

    [转载]http://www.cnblogs.com/dolphin0520/p/3920397.html 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDow ...

  7. Java并发编程: CountDownLatch、CyclicBarrier和 Semaphore

    java 1.5提供了一些非常有用的辅助类来帮助并发编程,比如CountDownLatch,CyclicBarrier和Semaphore. 1.CountDownLatch –主线程阻塞等待,最后完 ...

  8. Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore , Condition

    http://www.importnew.com/21889.html 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDown ...

  9. Java并发编程中的相关注解

    引自:http://www.cnblogs.com/phoebus0501/archive/2011/02/21/1960077.html Java并发编程中,用到了一些专门为并发编程准备的 Anno ...

随机推荐

  1. PS入门到精通完全自学教程

    ps视频教程,ps自学视频教程.ps免费视频教程下载,PS入门到精通完全自学教程视频内容较大,分为俩部分: PS入门到精通完全自学教程-第一部分(带swf播放器):百度网盘,https://pan.b ...

  2. Jupyter安装及运行

    一.安装(来自http://jupyter.org/install) Ctrl+Alt+T(Manjaro系统),打开控制台,su进入root权限 输入如下命令: python3 -m pip ins ...

  3. 宝塔中mysql数据库命名小坑

    今天在通过宝塔新建网站,添加mysql数据库,名字中间有下划线,发现能够创建成功,但是实际链接后,是没有这个数据库的.是宝塔的原因还是liunx服务器的原因? 不支持下划线的数据库名字吗? 比如 bo ...

  4. 1.21 贪心入门上午PAT例题题解

    1.B1023 #include<cstdio> int a[10]; int main() { for(int i=0;i<=9;i++) { scanf("%d&quo ...

  5. 《Redis设计与实现》阅读笔记(四)--字典

    字典 字典,map,是用于保存键值对的抽象数据结构,是hash表实现.字典中的键唯一,通过键来操作值.Redis的数据库使用字典来作为底层实现. 定义 Redis的字典使用哈希表作为底层实现,一个哈希 ...

  6. sklearn 中的 Pipeline 机制

    转载自:https://blog.csdn.net/lanchunhui/article/details/50521648 from sklearn.pipeline import Pipeline ...

  7. K-SVD字典学习及其实现(Python)

    算法思想 算法求解思路为交替迭代的进行稀疏编码和字典更新两个步骤. K-SVD在构建字典步骤中,K-SVD不仅仅将原子依次更新,对于原子对应的稀疏矩阵中行向量也依次进行了修正. 不像MOP,K-SVD ...

  8. Netty源码分析第6章(解码器)---->第1节: ByteToMessageDecoder

    Netty源码分析第六章: 解码器 概述: 在我们上一个章节遗留过一个问题, 就是如果Server在读取客户端的数据的时候, 如果一次读取不完整, 就触发channelRead事件, 那么Netty是 ...

  9. 2015第六届蓝桥杯C/C++ B组

    奖券数目:枚举 有些人很迷信数字,比如带“4”的数字,认为和“死”谐音,就觉得不吉利.虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求.某抽奖活动的奖券号码是5位数(10000-99999),要求其 ...

  10. PHP字符编码转换库iconv的一个细节

    先来看代码 <?php $charset = 'GBK'; $str = '中华人民共和国中华人民共和国中华人民共和国中华人民共和国'; ; $str2 = iconv('UTF-8', $ch ...