一,类介绍
这是java.util.concurrent包里的一个同步辅助类,它有两个主要的常用方法 countDown()方法以及await()方法。在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
这个类可以帮助我们做什么事呢?
二,实例运行
列举一个场景,三个人赛跑,哨声一响同时出发,跑到一半时A选手突然觉得拿名次没什么意思,当最后一名也挺好,然后他就让B,C先跑到终点,然后自己再跑。
这里我们可以开三个线程模拟三位选手,看看我们怎么通过这两个重要方法来实现A选手的想法的。
代码如下,不妨先复制一下,跑起来再说。
public classSample {/*** 计数器,用来控制线程
* 传入参数2,表示计数器计数为2*/
private final static CountDownLatch mCountDownLatch = new CountDownLatch(2);/*** A线程类*/
private static class ThreadA extendsThread {
@Overridepublic voidrun() {
System.out.println("A选手 出发!");try{//会阻塞在这里等待 mCountDownLatch 里的count变为0;//也就是等待另外的WorkingThread调用countDown()
mCountDownLatch.await();
}catch(InterruptedException e) {
}
System.out.println("A选手 到终点拉!");
}
}/*** BC线程类*/
private static class WorkingThread extendsThread {private finalString mThreadName;private final intmSleepTime;public WorkingThread(String name, intsleepTime) {
mThreadName=name;
mSleepTime=sleepTime;
}
@Overridepublic voidrun() {
System.out.println("[" + mThreadName + "] 出发!");try{
Thread.sleep(mSleepTime);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("[" + mThreadName + "] 到终点拉!");
mCountDownLatch.countDown();
}
}public static void main(String[] args) throwsException {//最先run ThreadA
newThreadA().start();new WorkingThread("B选手", 2000).start();new WorkingThread("C选手", 2000).start();
}
}
三,代码分析
现在我们来分析一下代码,我们先开启了A线程,它先跑了,但是在A线程的run方法中,调用了await()方法,这个方法可以让当前线程处于等待状态,直到计数器为0时,才继续往下执行。
好了计数器是什么东西,其实CountDownLatch这个类我们就可以把它看出一个计数器,实际上它内部也真实维护了一个count计数,对计数的操作都是原子的,啰嗦一句,原子操作的意思
就是当一个线程对count进行修改时,其他的线程是不可以同时修改的。上面说到要等到计数器为0才行,显然想让它为0,就得有个初始值,然后再有减的操作才行吧。赋初始值的操作,就是new这
个对象的时候就完成拉,代码中 new CountDownLatch(2) 就是给count设为2的操作,然后mCountDownLatch.countDown()这个方法就是count减去1的操作,代码我们减了两次,为0之后,A选手才继续跑完。
好了,这样的栗子好像只能帮助理解,但是挑不起兴趣,再举一个工作中真实用到的场景。
开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个线程来拼接所有的分段,那么这时候我们可以考虑使用CountDownLatch来控制并发,使得拼接的线程放在最后执行。