美文网首页
CountDownLatch 的作用、应用场景和实战

CountDownLatch 的作用、应用场景和实战

作者: wuchao226 | 来源:发表于2021-04-12 17:31 被阅读0次

    CyclicBarrier 的作用、应用场景和实战
    Semaphore 的作用、应用场景和实战

    CountDownLatch 概述

    CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。

    CountDownLatch 这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动 所有的框架服务之后再执行。

    CountDownLatch 是通过一个计数器来实现的,计数器的初始值为初始任务 的数量。每当完成了一个任务后,计数器的值就会减 1 (CountDownLatch.countDown()方法)。当计数器值到达 0 时,它表示所有的已 经完成了任务,然后在闭锁上等待 CountDownLatch.await()方法的线程就可以恢 复执行任务。

    使用原理

    1. 创建 CountDownLatch 并设置计数器值。
    2. 启动多线程并且调用 CountDownLatch 实例的 countDown() 方法。
    3. 主线程调用 await()方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务,count 值为 0,停止阻塞,主线程继续执行。

    CountDownLatch 用法

    CountDownLatch 类位于 java.util.concurrent 包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用 CountDownLatch 来实现这种功能了。

    CountDownLatch 类只提供了一个构造器:

    // 参数count为计数值
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    

    下面这3个方法是 CountDownLatch 类中最重要的方法:

     // 调用 await() 方法的线程会被挂起,它会等待直到 count 值为 0 才继续执行
    public void await() throws InterruptedException { };  
    // 和 await() 类似,若等待 timeout 时长后,count 值还是没有变为 0,不再等待,继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
    // 会将 count 减 1,直至为 0
    public void countDown() { }; 
    

    CountDownLatch 使用场景

    实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。 例如,我们想测试一个单例类。如果我们创建一个初始计数为 1 的 CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用一次 countDown() 方法就可以让所有的等待线程同时恢复执行。

    开始执行前等待 n 个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有 N 个外部系统已经启动和运行了,例如处理 excel 中多个表单。

    同时启动多个线程代码实现:

    public class UseCountDownLatch {
    
        static class TaskThread extends Thread {
            CountDownLatch latch;
    
            public TaskThread(CountDownLatch latch) {
                this.latch = latch;
            }
    
            @Override
            public void run() {
                super.run();
                try {
                    latch.await();
                    System.out.println(getName() + " start " + System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            int threadNum = 10;
            CountDownLatch latch = new CountDownLatch(1);
    
            for(int i = 0; i < threadNum; i++) {
                TaskThread task = new TaskThread(latch);
                task.start();
            }
    
            Thread.sleep(1000);
            latch.countDown();
        }
    }
    

    代码解释:

    • 设置 CountDownLatch 等待线程数为 1
    • 开启 10 个线程,每个线程都会调用 CountDownLatch 的 await() 方法,这样每个线程都会被阻塞
    • 主线程休眠 1 秒后,调用 CountDownLatch 的 countDown() 方法,调用后就会唤醒所有等待的线程,所有等待的线程就会同时执行

    打印结果:

    Thread-1 start 1618219648120
    Thread-6 start 1618219648120
    Thread-5 start 1618219648120
    Thread-8 start 1618219648120
    Thread-9 start 1618219648120
    Thread-7 start 1618219648120
    Thread-4 start 1618219648120
    Thread-3 start 1618219648120
    Thread-0 start 1618219648120
    Thread-2 start 1618219648120
    

    基本使用

    需求

    现在实现主线程等待其他线程的任务完成之后,才继续执行的代码。

    代码实现:

    public class UseCountDownLatch {
    
        static class TaskThread extends Thread {
            CountDownLatch latch;
    
            public TaskThread(CountDownLatch latch) {
                this.latch = latch;
            }
    
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(getName() + " Task is Done");
                    latch.countDown();
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            int threadNum = 10;
            CountDownLatch latch = new CountDownLatch(threadNum);
            for (int i = 0; i < threadNum; i++) {
                TaskThread taskThread = new TaskThread(latch);
                taskThread.start();
            }
            System.out.println("Task Start!");
    
            latch.await();
    
            System.out.println("All Task is Done!");
        }
    }
    

    代码解释:

    • 设置 CountDownLatch 的等待线程数为 10
    • 开启 10 个线程,每个线程都会睡眠 1 秒,睡眠结束后就会调用 CountDownLatch 的 countDown() 方法
    • 主线程调用 CountDownLatch 的 await() 方法,所以会开始阻塞,直到 CountDownLatch 的 count 为 0 才继续执行

    打印结果

    Task Start!
    Thread-5 Task is Done
    Thread-8 Task is Done
    Thread-4 Task is Done
    Thread-3 Task is Done
    Thread-9 Task is Done
    Thread-6 Task is Done
    Thread-0 Task is Done
    Thread-7 Task is Done
    Thread-1 Task is Done
    Thread-2 Task is Done
    All Task is Done!
    

    相关文章

      网友评论

          本文标题:CountDownLatch 的作用、应用场景和实战

          本文链接:https://www.haomeiwen.com/subject/xoyxlltx.html