概念

代码

demo1

import utils.SleepTools;

import java.util.concurrent.CountDownLatch;

/**
*
* 案例:ZJJ_JavaBasic_2020/10/19_19:22:55_dg8v8
* 类说明:演示CountDownLatch用法,
* 共5个初始化子线程,6个闭锁扣除点,扣除完毕后,主线程和业务线程才能继续执行
*/
public class Demo1 {

static CountDownLatch latch = new CountDownLatch(6); //定义初始化CTN计数器是6(6个闭锁扣除点)

/*初始化线程*/
private static class InitThread implements Runnable {

@Override
public void run() {
System.out.println("线程_" + Thread.currentThread().getId()
+ " 开始初始化工作......");
latch.countDown();//计数器减一
for (int i = 0; i < 2; i++) {
System.out.println("线程_" + Thread.currentThread().getId()
+ " ........继续做它的工作");
}
}
}

/*业务线程等待latch的计数器为0完成*/
private static class BusiThread implements Runnable {

@Override
public void run() {
try {
latch.await(); //等待方法,当这个被唤醒的时候意味着Latch数量被扣减为0了.
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 3; i++) {
System.out.println("业务线程_" + Thread.currentThread().getId()
+ " 开始业务-----");
}
}
}

public static void main(String[] args) throws InterruptedException {

new Thread(new Runnable() {
@Override
public void run() {
SleepTools.ms(1);
System.out.println("线程_" + Thread.currentThread().getId()
+ " 准备好初始化工作步骤1......");
latch.countDown();//扣减
System.out.println("开始步骤2.......");
SleepTools.ms(1);
System.out.println("线程_" + Thread.currentThread().getId()
+ " 准备初始化工作步骤3......");
latch.countDown();//扣减
}
}).start();

new Thread(new BusiThread()).start();

for (int i = 0; i <= 3; i++) {
Thread thread = new Thread(new InitThread());
thread.start();
}

latch.await(); //主线程也可以等待
System.out.println("Main线程开始它的工作了.........");
}
}

控制台打印:

线程_14 开始初始化工作......
线程_17 开始初始化工作......
线程_17 ........继续做它的工作
线程_17 ........继续做它的工作
线程_16 开始初始化工作......
线程_15 开始初始化工作......
线程_15 ........继续做它的工作
线程_15 ........继续做它的工作
线程_16 ........继续做它的工作
线程_14 ........继续做它的工作
线程_14 ........继续做它的工作
线程_16 ........继续做它的工作
线程_12 准备好初始化工作步骤1......
开始步骤2.......
线程_12 准备初始化工作步骤3......
Main线程开始它的工作了.........
业务线程_13 开始业务-----
业务线程_13 开始业务-----
业务线程_13 开始业务-----

展现的效果是, 业务线程会在初始化线程全部执行完初始化工作,业务线程才开始进行执行业务代码

demo2

import utils.SleepTools;

import java.util.concurrent.CountDownLatch;

/**
*案例:ZJJ_JavaBasic_2020/10/19_19:22:55_dg8v8
*
* boss线程必须等待work线程执行完了, 计数器变为0的时候 boss线程才能开始工作.
*/
public class Demo2 {


static CountDownLatch latch = new CountDownLatch(2);


public static void main(String[] args) {


Thread boss1 = new Thread("boss1") {
@Override
public void run() {
System.out.println("[boss线程] 线程开始执行了");
try {
System.out.println("[boss线程] 线程准备阻塞等待子线程完成工作!!!!");
latch.await();
System.out.println("[boss线程] 子线程完成工作了,boss1线程开始唤醒继续工作!!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}

}
};


Thread worker1 = new Thread("worker1") {
@Override
public void run() {
System.out.println("work1线程开始执行了");
SleepTools.second(3);
long count = latch.getCount();
System.out.println("当前的计数器 :" + count);

System.out.println("work1线程执行结束,计数器准备减一");
latch.countDown();

}
};

Thread worker2 = new Thread("worker2") {
@Override
public void run() {
System.out.println("work2线程开始执行了");
SleepTools.second(3);
long count = latch.getCount();
System.out.println("当前的计数器 :" + count);

System.out.println("work2线程执行结束,计数器准备减一");
latch.countDown();
}
};
boss1.start();
worker1.start();
worker2.start();


}
}

控制台打印的结果:

[boss线程] 线程开始执行了
[boss线程] 线程准备阻塞等待子线程完成工作!!!!
work2线程开始执行了
work1线程开始执行了
当前的计数器 :2
work1线程执行结束,计数器准备减一
当前的计数器 :2
work2线程执行结束,计数器准备减一
[boss线程] 子线程完成工作了,boss1线程开始唤醒继续工作!!!!

看控制台打印结果
当boss启动了,发现work线程都还没执行完毕,boss线程此时会被阻塞.
, 当work线程全部执行完毕之后,boss线程就被唤醒,开始工作