基础巩固篇 —— 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队列抽象类。

原文地址:https://www.cnblogs.com/zzb-yp/p/15045690.html