1、简单介绍
CountDownLatch(以后简称为cdl)这个类能够是一个线程或者多个线程等待其他的线程完成各自的业务工作再执行。比如:应用程序中的主线程希望在负责启动框架服务的线程,已经启动所有的框架服务之后再执行。
cdl是通过继承aqs(是java对CLH队列锁思想的一种实现,通过模板设计模式的方式让用户实现线程同步的工具,例如ReentrantLock也是继承aqs)来实现自身功能,内部通过一个计数器来实现,计数器的初始值为初始的任务量,每完成一个任务需要调用cdl.countDown()方法,让计数器-1。
有时候我们像同事启动多个线程,实现最大程度的并行性,如果我们创建一个初始计数为1的cdl,并让所有的线程在这个锁上等待,那么我们可以很轻松的完成测试。我们只需要一次countDown()方法就可以让所有的线程同事恢复执行,前提需要在等待线程中调用await()方法。
测试代码,我初始化了6个计数器,分别在主线程调用2次countDown(),在业务线程中调用4次countDown(),并在主线程和其他业务线程中都调用了await()各一个方法。看代码:
/**
*类说明:演示CountDownLatch用法,
* 共5个初始化子线程,6个闭锁扣除点,扣除完毕后,主线程和业务线程才能继续执行
*/
public class UseCountDownLatch {
static CountDownLatch latch = new CountDownLatch(6);
/*初始化线程*/
private static class InitThread implements Runnable{
public void run() {
System.out.println("Thread_"+Thread.currentThread().getId()
+" 初始化工作......");
for(int i =0;i<2;i++) {
System.out.println("Thread_"+Thread.currentThread().getId()
+" ........继续工作");
}
latch.countDown();
}
}
/*业务线程等待latch的计数器为0完成*/
private static class BusiThread implements Runnable {
public void run() {
try {
System.out.println("业务线程等待工作");
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i =0;i<3;i++) {
SleepTools.ms(1);
System.out.println("BusiThread_"+Thread.currentThread().getId()
+" 业务线程工作-----");
}
}
}
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
public void run() {
SleepTools.ms(1);
System.out.println("Thread_"+Thread.currentThread().getId()
+" 第一次准备......");
latch.countDown();
SleepTools.ms(1);
System.out.println("Thread_"+Thread.currentThread().getId()
+" 第二次准备......");
System.out.println("初始化工作");
SleepTools.ms(1);
latch.countDown();
System.out.println("-----------------大家开始工作-----------------------");
SleepTools.ms(1);
System.out.println("Thread_"+Thread.currentThread().getId()+"....." +
"工作");
}
}).start();
new Thread(new BusiThread()).start();
for(int i=0;i<=3;i++){
Thread thread = new Thread(new InitThread());
thread.start();
}
latch.await();
Thread.sleep(1000);
System.out.println("主线程开始正式工作........");
}
}
public class SleepTools {
/**
* 按秒休眠
* @param seconds 秒数
*/
public static final void second(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
}
}
/**
* 按毫秒数休眠
* @param seconds 毫秒数
*/
public static final void ms(int seconds) {
try {
TimeUnit.MILLISECONDS.sleep(seconds);
} catch (InterruptedException e) {
}
}
}