CountDownLatch详解(用法原理及应用示例)

CountDownLatch详解(用法原理及应用示例)-mikechen

CountDownLatch定义

CountDownLatch是一个同步工具类,CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。

CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrierSemaphoreConcurrentHashMap阻塞队列BlockingQueue

 

CountDownLatch作用

CountDownLatch的作用很简单,就是一个或者一组线程在开始执行操作之前,必须要等到其他线程执行完才可以。

例如:应用程序的主线程,希望在负责启动框架服务的线程,启动所有的框架服务之后,最后再执行。

除了刚提到的技术场景,生活中场景也是非常多的,比如:在考试的时候,老师必须要等到所有人交了试卷才可以走。

 

CountDownLatch实现原理

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。

每当一个线程完成了自己的任务后,计数器的值就会减1,当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

如下图所示:

CountDownLatch详解(用法原理及应用示例)-mikechen

整个的实现步骤,大致可以分为如下3步:

第一步:初始计数器

// 等待线程的数量为10
CountDownLatch c = new CountDownLatch(10);

第二步:主线程阻塞

此时,主线程调用CountDownLatch的await()方法,阻塞当前线程(即:主线程在闭锁上等待),直到计数器的值为0。

//主线程在闭锁上等待,直到计数器的值为0
countDownLatch.await()

第三步:计数器减1

主线程闭锁等待后,子线程开始执行任务,每当一个线程完成了自己的任务后,调用CountDownLatch的countDown()方法,计数器的值就会减1,如下所示:

//countDown():计数器减一,表示线程完成任务
CountDownLatch.countDown()

上面的初始线程10陆续减完,当计数器值到达0时,它表示所有的线程已经完成了任务,此时,在闭锁上等待的主线程就可以恢复执行任务。

 

CountDownLatch使用示例

这里举个例子,例如:在比赛跑步时有 5 个运动员参赛,终点有一个裁判员,什么时候比赛结束呢?那就是当所有人都跑到终点之后,宣布比赛结束。

示例如下:

public class CountDownLatchDemo{

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(5);
        ExecutorService service = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            final int no = i + 1;
            Runnable runnable = new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println(no + "号运动员完成了比赛。");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            };
            service.submit(runnable);
        }
        System.out.println("等待5个运动员都跑完.....");
        latch.await();
        System.out.println("所有人都跑完了,比赛结束。");
    }
}

在这段代码中,我们新建了一个初始值为 5 的 CountDownLatch。

主线程打印完“等待 5 个运动员都跑完”这句话后,会调用 await() 方法,代表让主线程开始等待。

每个任务代表:一个运动员,每个运动员跑完比赛,会调用 countDown 方法来把计数减 1。

执行结果如下:

CountDownLatch详解(用法原理及应用示例)-mikechen

主线程等待所有运动员都跑完比赛后,直到 5 个运动员都完成了比赛之后,也就是说直到计数器为0,主线程才会继续。

 

CountDownLatch应用场景

倒数计时器,例如:一种典型的场景就是火箭发射,在火箭发射前,为了保证万无一失,往往还要进行各项设备、仪器的检查。

只有等所有检查完毕后,引擎才能点火,这种场景就非常适合使用。

同样,应用程序的主线程,希望启动所有的框架的子线程执行完后,最后再执行主线程,这种场景也是非常适合的。

 

 

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法