一、 CountDownLatch是什么
CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier
、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。
正如Java文档所描述的那样,CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
CountDownLatch工作过程
CountDownLatch工作过程的伪代码如下所示:
1. 启动主线程
2. 为即将运行的N个子线程创建一个CountDownLatch
3. 创建并且运行N个子线程
4. 主线程调用CountDownLatch.await()方法,进入等待状态
5. 当N个线程都调用了CountDownLatch.countDown()方法,count的值等于0
6. 主线程被重新唤醒,继续工作
二、主要方法
public CountDownLatch(int count); //指定计数的次数,只能被设置1次
public void countDown(); //调用此方法则计数减1
public void await() throws InterruptedException //调用此方法会一直阻塞当前线程,直到计时器的值为0,除非线程被中断。
Public Long getCount(); //得到当前的计数
Public boolean await(long timeout, TimeUnit unit) //调用此方法会一直阻塞当前线程,直到计时器的值为0,除非线程被中断或者计数器超时,返回false代表计数器超时。
From Object Inherited:
Clone、equals、hashCode、notify、notifyALL、wait等。
三、应用场景
(1)开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个线程来拼接所有的分段。
(2)应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
(3)确保一个计算不会执行,直到所需要的资源被初始化。
四、简单示例
我们模拟一个启动类TestCountDownLatch,在类中启动两个子线程AThread、BThread执行任务,此时启动类进入到等待状态,只有当子线程任务全部执行完毕,启动类才会继续执行下去。
BaseThread 基础线程类,用于模拟多线程任务:
package qianwei.android.javaproject.countdownlatch;
import java.util.concurrent.CountDownLatch;
public abstract class BaseThread implements Runnable {
private String name;
private CountDownLatch countDownLatch;
public BaseThread(String name, CountDownLatch countDownLatch) {
this.name = name;
this.countDownLatch = countDownLatch;
}
public String getName() {
return name;
}
@Override
public void run() {
try {
System.out.println(getName() + " start...");
doWork();
System.out.println(getName() + " done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
}
public abstract void doWork();
}
创建AThread、BThread任务,直接继承BaseThread重写任务执行方法doWork():
public class AThread extends BaseThread {
public AThread(String name, CountDownLatch countDownLatch) {
super(name, countDownLatch);
}
@Override
public void doWork() {
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class BThread extends BaseThread {
public BThread(String name, CountDownLatch countDownLatch) {
super(name, countDownLatch);
}
@Override
public void doWork() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
主启动类TestCountDownLatch:
public class TestCountDownLatch {
private static CountDownLatch countDownLatch;
private static List<BaseThread> baseThreadList = new ArrayList<>();
public static void main(String[] args) {
test();
}
private static void test() {
countDownLatch = new CountDownLatch(2);
baseThreadList.add(new AThread("AThread", countDownLatch));
baseThreadList.add(new BThread("BThread", countDownLatch));
Executor executor = Executors.newFixedThreadPool(baseThreadList.size());
for (BaseThread baseThread : baseThreadList) {
executor.execute(baseThread);
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test finished.");
}
}
执行结果
BThread start...
AThread start...
BThread done!
AThread done!
test finished.
网友评论