一,类介绍
这是java.util.concurrent包里的一个同步辅助类,它有两个主要的常用方法 countDown()方法以及await()方法。在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
这个类可以帮助我们做什么事呢?
二,实例运行
列举一个场景,三个人赛跑,哨声一响同时出发,跑到一半时A选手突然觉得拿名次没什么意思,当最后一名也挺好,然后他就让B,C先跑到终点,然后自己再跑。
这里我们可以开三个线程模拟三位选手,看看我们怎么通过这两个重要方法来实现A选手的想法的。
代码如下,不妨先复制一下,跑起来再说。
public class Sample { /**
* 计数器,用来控制线程
* 传入参数2,表示计数器计数为2
*/
private final static CountDownLatch mCountDownLatch = new CountDownLatch(2); /**
* A线程类
*/
private static class ThreadA extends Thread { @Override
public void run() {
System.out.println("A选手 出发!");
try {
// 会阻塞在这里等待 mCountDownLatch 里的count变为0;
// 也就是等待另外的WorkingThread调用countDown()
mCountDownLatch.await();
} catch (InterruptedException e) { }
System.out.println("A选手 到终点拉!");
}
} /**
* BC线程类
*/
private static class WorkingThread extends Thread {
private final String mThreadName;
private final int mSleepTime;
public WorkingThread(String name, int sleepTime) {
mThreadName = name;
mSleepTime = sleepTime;
} @Override public void run() {
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) throws Exception {
// 最先run ThreadA
new ThreadA().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来控制并发,使得拼接的线程放在最后执行。