java并发笔记之--CountDownLatch
本文为java并发笔记系列之--- CountDownLatch
概念
单词Latch,中文翻译是门闩,也就是有“门锁”的功能,所以当门没有打开时,N个人是不能进入屋内的,也就是N个线程是不能继续向下运行的,支持这样的特性可以控制线程执行任务的时机,使线程以“组团”的方式一起执行任务。
类CountDownLatch也是一个同步功能的辅助类,使用效果是给定一个计数,当使用这个CountDownLatch类的线程判断计数不为0时,则呈wait状态,如果为0时则继续运行
使用场景
接下来借助百米短跑场景进行讲解使用场景。
- 首先裁判需要等待所有的运动员到场
- 然后运动员等待裁判发起准备信号
- 裁判等待所有运动员准备就绪,裁判发起起跑信号
- 裁判等待运动员全部跑完
- 裁判宣布比赛结束
实现代码如下所示
package com.shunwang.swbox.show.service;
import java.util.concurrent.CountDownLatch;
/**
* 短跑运动员
*
* @author ljs.song
* @date 2017-11-08 19:08
*/
public class RunerPepole extends Thread{
//运动员达起点过程
private CountDownLatch comingTag;
//运动员等待裁判准备信号
private CountDownLatch waitTag;
//运动员等待裁判起跑信号
private CountDownLatch waitRunTag;
//运动员等待裁判说起跑
private CountDownLatch beginTag;
//运动员到达终点
private CountDownLatch endTag;
public RunerPepole(CountDownLatch comingTag, CountDownLatch waitTag, CountDownLatch waitRunTag, CountDownLatch beginTag, CountDownLatch endTag) {
super();
= comingTag;
this.waitTag = waitTag;
this.waitRunTag = waitRunTag;
this.beginTag = beginTag;
this.endTag = endTag;
}
@Override
public void run() {
System.out.println("运动员"+Thread.currentThread().getName() + "正在骑车赶到起点");
try {
Thread.sleep(2000);
System.out.println("运动员"+Thread.currentThread().getName() + "到达起点,等待准备");
comingTag.countDown();
waitTag.await();
System.out.println("运动员"+Thread.currentThread().getName() + "正在准备……");
Thread.sleep(1000);
waitRunTag.countDown();
//等待裁判起跑信号
beginTag.await();
System.out.println("运动员"+Thread.currentThread().getName() + "到达终点******");
endTag.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 裁判端
* @param args
*/
public static void main(String[] args) {
CountDownLatch comintTag = new CountDownLatch(10);
CountDownLatch waitTag = new CountDownLatch(1);
CountDownLatch waitRunTag = new CountDownLatch(10);
CountDownLatch beginTag = new CountDownLatch(1);
CountDownLatch endTag = new CountDownLatch(10);
RunerPepole[] runerPepoles = new RunerPepole[10];
for (int i = 0; i < 10; i++) {
runerPepoles[i] = new RunerPepole(comintTag, waitTag, waitRunTag, beginTag, endTag);
runerPepoles[i].start();
}
try {
System.out.println("裁判等待所有运动员到场");
comintTag.await();
//裁判发起准备信号
System.out.println("裁判发起准备信号");
waitTag.countDown();
System.out.println("裁判检查等待所有人准备完成");
waitRunTag.await();
System.out.println("裁判发起起跑信号--------------");
beginTag.countDown();
endTag.await();
System.out.println("所有运动员到达终点,比赛结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
运动员Thread-0正在骑车赶到起点
运动员Thread-4正在骑车赶到起点
运动员Thread-2正在骑车赶到起点
运动员Thread-6正在骑车赶到起点
运动员Thread-1正在骑车赶到起点
裁判等待所有运动员到场
运动员Thread-3正在骑车赶到起点
运动员Thread-5正在骑车赶到起点
运动员Thread-7正在骑车赶到起点
运动员Thread-9正在骑车赶到起点
运动员Thread-8正在骑车赶到起点
运动员Thread-1到达起点,等待准备
运动员Thread-5到达起点,等待准备
运动员Thread-9到达起点,等待准备
运动员Thread-4到达起点,等待准备
运动员Thread-8到达起点,等待准备
运动员Thread-0到达起点,等待准备
运动员Thread-3到达起点,等待准备
运动员Thread-6到达起点,等待准备
运动员Thread-2到达起点,等待准备
运动员Thread-7到达起点,等待准备
裁判发起准备信号
裁判检查等待所有人准备完成
运动员Thread-1正在准备……
运动员Thread-5正在准备……
运动员Thread-9正在准备……
运动员Thread-4正在准备……
运动员Thread-8正在准备……
运动员Thread-0正在准备……
运动员Thread-3正在准备……
运动员Thread-6正在准备……
运动员Thread-2正在准备……
运动员Thread-7正在准备……
裁判发起起跑信号--------------
运动员Thread-1到达终点******
运动员Thread-5到达终点******
运动员Thread-9到达终点******
运动员Thread-4到达终点******
运动员Thread-8到达终点******
运动员Thread-0到达终点******
运动员Thread-7到达终点******
运动员Thread-3到达终点******
运动员Thread-6到达终点******
运动员Thread-2到达终点******
所有运动员到达终点,比赛结束
Process finished with exit code 0
如上结果可以看到,所有的10个运动员在每个节点未拿到信号前,都处于等待(阻塞)状态,然后拿到信号后,指定数量的运动员(线程)一起开始运行,这样能达到上述概念中描述的“门锁”的概念,方便我们工作场景中灵活控制