Java并发31:CountDownLatch(下)--两种应用场景

Java并发30:CountDownLatch(上)–基本方法学习

[超级链接:Java并发学习系列-绪论]


本章主要对CountDownLatch的两种应用场景进行学习。

有关CountDownLatch的基本方法详见上一章:《 Java并发30》

1.用法概述

本人所知的CountDownLatch的用法主要有以下两个方面:

  • 开关/哨子(初始count=1):所有调用它的await()方法的线程都会等待,直到开关打开(执行一次countDown())。强调的是同时二字。
  • 计数器/总闸(初始count=n):所有调用它的countDown()方法的线程都会使count减1,直到为0,释放所有线程。强调的是多个二字。

下面分别对这两种应用场景进行实例练习。

2.跑步比赛(初始count=1)

场景说明:

  • 这是一场在田径赛场举行的跑步比赛。
  • 田径赛场共有10个跑道。
  • 当10名参赛选手在跑道起点就位后,裁判会倒计时,并最终吹响哨子。
  • 当听到哨声之后,10名参赛选手同时起跑。
  • 10名参赛选手根据不同的身体素质,耗费不同的时间到达终点。

重点分析:

  • 田径赛场共有10个跑道:需要定义一个初始大小为10的线程池
  • 哨子:需要定义一个初始count=1的CountDownLatch对象。
  • 并最终吹响哨子:即执行一次countDown()方法

实例代码:

运动员:

/**
* 

运动员

* * @author hanchao 2018/3/28 20:48 **/
static class Player implements Runnable { private static final Logger LOGGER = Logger.getLogger(Player.class); /** * 哨子 */ CountDownLatch latch; public Player(CountDownLatch latch) { this.latch = latch; } @Override public void run() { String name = Thread.currentThread().getName(); //等待吹哨 LOGGER.info("Player[" + name + "] is waiting for the whistle."); try { //注意是await(),不是wait()。 //前置是CountDownLatch的方法,后者是Object的方法。 latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("Player[" + name + "] is running..."); //跑到终点的时间 Integer time = RandomUtils.nextInt(5000, 9000); try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("Player[" + name + "] is has arrived the finish line!"); } }

裁判:

/**
 * 

裁判员

* * @author hanchao 2018/3/28 20:48 **/
static class Referee implements Runnable { private static final Logger LOGGER = Logger.getLogger(Referee.class); /** * 哨子 */ CountDownLatch latch; public Referee(CountDownLatch latch) { this.latch = latch; } @Override public void run() { String name = Thread.currentThread().getName(); //准备吹哨 LOGGER.info("Referee[" + name + "] is ready to whistle. 3... 2... 1...!"); //裁判吹哨--countDown()使count减1,当count=0时,所有在latch上await()的线程不再等待 latch.countDown(); } }

比赛代码:

 /**
* 

倒计时门闩-示例

* * @author hanchao 2018/3/28 20:52 **/
public static void main(String[] args) throws InterruptedException { //示例一:跑步比赛---哨子 //创建 哨子 CountDownLatch latch = new CountDownLatch(1); //创建 10人赛道 int num = 10; ExecutorService executorService = Executors.newFixedThreadPool(num); //运动员上赛道 for (int i = 0; i < num; i++) { executorService.submit(new Player(latch)); } //裁判准备 Thread.sleep(1000); //裁判开始吹哨 new Thread(new Referee(latch)).start(); //等所有人都跑完,关闭跑道 Thread.sleep(10000); executorService.shutdownNow(); }

运行结果:

2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-1] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-2] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-3] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-10] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-9] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-8] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-7] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-6] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-5] is waiting for the whistle.
2018-03-31 22:42:11 INFO  CountDownLatchDemo1$Player:46 - Player[pool-1-thread-4] is waiting for the whistle.
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Referee:86 - Referee[Thread-0] is ready to whistle. 3... 2... 1...!
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-1] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-6] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-4] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-5] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-7] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-8] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-9] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-10] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-2] is running...
2018-03-31 22:42:12 INFO  CountDownLatchDemo1$Player:54 - Player[pool-1-thread-3] is running...
2018-03-31 22:42:17 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-9] is has arrived the finish line!
2018-03-31 22:42:18 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-8] is has arrived the finish line!
2018-03-31 22:42:18 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-6] is has arrived the finish line!
2018-03-31 22:42:18 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-10] is has arrived the finish line!
2018-03-31 22:42:19 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-7] is has arrived the finish line!
2018-03-31 22:42:19 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-2] is has arrived the finish line!
2018-03-31 22:42:19 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-5] is has arrived the finish line!
2018-03-31 22:42:20 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-4] is has arrived the finish line!
2018-03-31 22:42:20 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-1] is has arrived the finish line!
2018-03-31 22:42:21 INFO  CountDownLatchDemo1$Player:62 - Player[pool-1-thread-3] is has arrived the finish line!

3.战神金刚(初始count=n)

场景说明:

  • 模拟儿时看到一部动画片《战神金刚》的变身过程。
  • 战神金刚有五个机器狮子组成,这五个机器狮子可以变形成战神金刚身体的一部分:腿、脚、躯干、手臂、头。
  • 当战神金刚的身体组装完成在一起之后,会大喊:前进,战神金刚!
  • 原版口号:组成腿和脚,组成躯干和手臂, 我来组成头部!-->前进,战神金刚!
  • 程序版口号:我来组成[手臂]!我来组成[头部]!我来组成[脚部]!我来组成[躯干]!我来组成[腿部]! -->前进,战神金刚!

重点分析:

  • 战神金刚有五个机器狮子组成:需要定义一个初始大小为5的线程池
  • 组装完成之后,会大喊:需要定义一个初始count=5的CountDownLatch对象。
  • 组装:每个部件的组装,即执行一次countDown()方法

实例代码:

机器狮子:

/**
* 

机器狮子

* @author hanchao 2018/3/31 23:02 **/
static class MachineLion implements Runnable { private static final Logger LOGGER = Logger.getLogger(MachineLion.class); //身体部分 private String name; //变形计数器 CountDownLatch latch; public MachineLion(String name, CountDownLatch latch) { this.name = name; this.latch = latch; } @Override public void run() { //花费一些时间进行组装 Integer time = RandomUtils.nextInt(0, 2000); LOGGER.info(Thread.currentThread().getName() + " [" + name + "] 正在进行组装..."); try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); LOGGER.info(Thread.currentThread().getName() + " 我来组成[" + name + "]!"); } }

战神金刚进行变身:

/**
* 

CountDownLatch用法2-线程计数器-战神金刚

* * @author hanchao 2018/3/28 21:34 **/
public static void main(String[] args) throws InterruptedException { //main就是战神金刚 int num = 5; //定义 变形计数器 CountDownLatch latch = new CountDownLatch(num); //定义 线程池 ExecutorService executorService = Executors.newFixedThreadPool(num); //五个机器狮子纷纷开始组装 executorService.submit(new MachineLion("脚部", latch)); executorService.submit(new MachineLion("腿部", latch)); executorService.submit(new MachineLion("躯干", latch)); executorService.submit(new MachineLion("手臂", latch)); executorService.submit(new MachineLion("头部", latch)); //等待五个机器狮子进行组装 LOGGER.info(Thread.currentThread().getName() + " [战神金刚] 正在等待组装..."); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } Thread.sleep(100); //战神金刚开始发威 LOGGER.info(Thread.currentThread().getName() + ": 前进,战神金刚!"); executorService.shutdownNow(); }

运行结果:

2018-03-31 22:59:52 INFO  CountDownLatchDemo2:75 - main [战神金刚] 正在等待组装...
2018-03-31 22:59:52 INFO  CountDownLatchDemo2$MachineLion:45 - pool-1-thread-2 [腿部] 正在进行组装...
2018-03-31 22:59:52 INFO  CountDownLatchDemo2$MachineLion:45 - pool-1-thread-4 [手臂] 正在进行组装...
2018-03-31 22:59:52 INFO  CountDownLatchDemo2$MachineLion:45 - pool-1-thread-3 [躯干] 正在进行组装...
2018-03-31 22:59:52 INFO  CountDownLatchDemo2$MachineLion:45 - pool-1-thread-5 [头部] 正在进行组装...
2018-03-31 22:59:52 INFO  CountDownLatchDemo2$MachineLion:45 - pool-1-thread-1 [脚部] 正在进行组装...
2018-03-31 22:59:53 INFO  CountDownLatchDemo2$MachineLion:52 - pool-1-thread-5 我来组成[头部]!
2018-03-31 22:59:53 INFO  CountDownLatchDemo2$MachineLion:52 - pool-1-thread-4 我来组成[手臂]!
2018-03-31 22:59:53 INFO  CountDownLatchDemo2$MachineLion:52 - pool-1-thread-1 我来组成[脚部]!
2018-03-31 22:59:54 INFO  CountDownLatchDemo2$MachineLion:52 - pool-1-thread-2 我来组成[腿部]!
2018-03-31 22:59:54 INFO  CountDownLatchDemo2$MachineLion:52 - pool-1-thread-3 我来组成[躯干]!
2018-03-31 22:59:54 INFO  CountDownLatchDemo2:83 - main: 前进,战神金刚!

你可能感兴趣的:(Java并发,Java并发学习实例)