作用
CountDownLatch允许一个或多个线程等待其他线程完成操作,相当于一个加强版的join方法。
核心方法
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完 成,这里就传入N。
- countDown:负责计数器的减一
- await:阻塞当前线程,直到CountDownLatch计数器变成零
由于countDown方法可以用在任何地方,所以这里说的N个 点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,只需要把这个 CountDownLatch的引用传递到线程里即可。
CountDownLatch使用了AQS来做实现,countDown就是对AQS的state值减一,await就是去验证state是否等于0。
示例
启动一个主线程,需要等到其他子线程初始化完毕
package com.xiaolyuh;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 5个初始化线程,6个扣除点,初始化完成后业务线程和住线程才能执行
*
* @author yuhao.wang3
* @since 2019/6/26 15:24
*/
public class CountDownLatchTest {
static final CountDownLatch countDownLatch = new CountDownLatch(6);
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "主线程开始......");
new Thread(new InitJob()).start();
new Thread(new BusinessWoerk()).start();
new Thread(new InitJob()).start();
new Thread(new InitWoerk()).start();
new Thread(new InitJob()).start();
new Thread(new InitJob()).start();
try {
System.out.println(Thread.currentThread().getName() + "主线程等待初始化线程初始化完成......");
countDownLatch.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
sleep(5);
System.out.println(Thread.currentThread().getName() + "主线程结束......");
}
/**
* 一个线程一个扣减点
*/
static class InitJob implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "初始化任务开始。。。。。。");
try {
sleep(5);
} finally {
countDownLatch.countDown();
}
sleep(5);
System.out.println(Thread.currentThread().getName() + "初始化任务完毕后,处理业务逻辑。。。。。。");
}
}
/**
* 一个线程两个扣减点
*/
static class InitWoerk implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "初始化工作开始第一步》》》》》");
try {
sleep(5);
} finally {
countDownLatch.countDown();
}
System.out.println(Thread.currentThread().getName() + "初始化工作开始第二步》》》》》");
sleep(5);
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName() + "初始化工作处理业务逻辑》》》》》");
}
}
/**
* 业务线程
*/
static class BusinessWoerk implements Runnable {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "初始化线程还未完成,业务线程阻塞----------");
countDownLatch.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "初始化工作完成业务线程开始工作----------");
System.out.println(Thread.currentThread().getName() + "初始化工作完成业务线程开始工作----------");
System.out.println(Thread.currentThread().getName() + "初始化工作完成业务线程开始工作----------");
System.out.println(Thread.currentThread().getName() + "初始化工作完成业务线程开始工作----------");
}
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
main主线程开始......
main主线程等待初始化线程初始化完成......
Thread-0初始化任务开始。。。。。。
Thread-1初始化线程还未完成,业务线程阻塞----------
Thread-2初始化任务开始。。。。。。
Thread-3初始化工作开始第一步》》》》》
Thread-4初始化任务开始。。。。。。
Thread-5初始化任务开始。。。。。。
Thread-3初始化工作开始第二步》》》》》
Thread-0初始化任务完毕后,处理业务逻辑。。。。。。
Thread-3初始化工作处理业务逻辑》》》》》
Thread-2初始化任务完毕后,处理业务逻辑。。。。。。
Thread-4初始化任务完毕后,处理业务逻辑。。。。。。
Thread-5初始化任务完毕后,处理业务逻辑。。。。。。
Thread-1初始化工作完成业务线程开始工作----------
Thread-1初始化工作完成业务线程开始工作----------
Thread-1初始化工作完成业务线程开始工作----------
Thread-1初始化工作完成业务线程开始工作----------
main主线程结束......
参考
《java并发编程的艺术》
源码
https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases
spring-boot-student-concurrent 工程
layering-cache
为监控而生的多级缓存框架 layering-cache这是我开源的一个多级缓存框架的实现,如果有兴趣可以看一下