基础巩固篇 —— CountDownLatch的理解
一、CountDownLatch是什么
CountDownLatch是java.util.concurrent包下的类。它可以使线程处于等候状态,当任务执行数量递减为0时,自动唤醒等待线程。这样可以控制多线程的执行顺序。
二、CountDownLatch的使用
private Integer task1_sum = 0;
private Integer task2_sum = 0;
private Integer task3_sum = 0;
private CountDownLatch countDownLatch = new CountDownLatch(2);
// 第一个任务,从 1 加到 10
public void task_1() {
System.out.println("执行第一个任务");
for (int i = 1; i < 10; i++) {
task1_sum += i;
}
// countDownLatch递减,由 2 变为 1
countDownLatch.countDown();
}
// 第二个任务,从 45 加到 55,执行时间超过3秒是为了与使用前对比
public void task_2() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("执行第二个任务task1_sum为:" + task1_sum);
Integer temp = task1_sum;
for (int i = temp; i < temp + 10; i++) {
task2_sum = task2_sum + i;
}
// countDownLatch递减,由 1 变为 0
countDownLatch.countDown();
}
// 第三个任务,从 495 加到 505
public void task_3() throws InterruptedException {
// 执行到此,线程等待,等countDownLatch值递减为0,也就是其他任务已经完成后,自动唤醒执行后面的操作
countDownLatch.await();
System.out.println("执行第三个任务task2_sum为:" + task2_sum);
Integer temp = task2_sum;
for (int i = temp; i < temp + 10; i++) {
task3_sum += i;
}
}
// 先执行任务一和二,再执行任务三
public void task_run() throws InterruptedException {
this.task_1();
new Thread(() -> {
try {
this.task_2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "aa").start();
this.task_3();
}
public static void main(String[] args) throws InterruptedException {
CountDownLatchDemo demo = new CountDownLatchDemo();
demo.task_run();
}
使用CountDownLatch后执行顺序正确:
执行第一个任务
执行第二个任务task1_sum为:45
执行第三个任务task2_sum为:495
未使用CountDownLatch时,执行顺序错误:
执行第一个任务
执行第三个任务task2_sum为:0
执行第二个任务task1_sum为:45
一共有三个任务,因为任务二执行时间最长且异步,正常执行一定是先执行任务一三,最后执行完二。为了保证按顺序执行,可以使用CountDownLatch,初始设置任务数2,进入任务三线程进入等候状态,当任务二执行完任务数也递减为0,然后自动唤醒执行任务三线程。这样就控制了执行顺序。
三、个人观点
这种自动唤醒的方式,感觉跟阻塞队列类似。一看源码:
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
其内部类Sync果然继承了AbstractQueuedSynchronizer队列抽象类。