• Java随笔-CountDownLatch


    概述

    CountDownLatch其实就是一个计数器,用来同步一个或多个任务,强制任务按步骤执行,多用来协调多线程。也就是一个任务想要执行,必须要等其他任务执行完后才能执行。
    CountDownLatch需要设置任务初始值,也就是需要执行的任务需要分几步执行,初始值就设为几,当计数值不为0的时候,任何一个对象调用wait()都将被阻塞,每一个步骤执行完毕后,调用countDown()计数都会减一。
    调用countDown()的任务在调用时没有被阻塞,只有调用wait()才会被阻塞,一直到计数值为0。
    该思想并非只在并发中使用,实际开发中很多场景也会使用相似的方法。

    使用

    方法解读

    CountDownLatch非常简单,只有几个方法。
    在这里插入图片描述

    • await(), 等待计数器的值为0,若为0就返回,如果不为0就阻塞。
    • await(long timeout, TimeUnit unit),在指定时间内等待计数器的值为0,若为0,则返回true,若不为0,则返回false。
    • countDown(),计数减1,若减1之前为1,则置为0,且唤醒所有等待的线程;若减1之前为0,则啥也不做。
    • getCount(),获取当前计数的值。

    使用

    1. 创建线程。
      产品经理:
    public class ProductManager extends Thread {
        private CountDownLatch countDown;
    
        public ProductManager(CountDownLatch countDown) {
            this.countDown = countDown;
        }
    
        @Override
        public void run() {
            if(countDown.getCount() != 4){
                try {
                    countDown.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("俺是产品经理,俺是提需求的");
            countDown.countDown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    UI设计:

    public class UI extends Thread {
        private CountDownLatch countDown;
    
        public UI(CountDownLatch countDown) {
            this.countDown = countDown;
        }
    
        @Override
        public void run() {
            if(countDown.getCount() != 3){
                try {
                    countDown.await(1000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("俺是设计,俺是设计界面的");
            countDown.countDown();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    开发:

    public class Developer extends Thread {
        private CountDownLatch countDown;
    
        public Developer(CountDownLatch countDown) {
            this.countDown = countDown;
        }
    
        @Override
        public void run() {
            if(countDown.getCount() != 2){
                try {
                    countDown.await(2000, TimeUnit.MILLISECONDS);
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("俺是开发,俺是干活的");
            countDown.countDown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    测试:

    public class Test extends Thread {
        private CountDownLatch countDown;
    
        public Test(CountDownLatch countDown) {
            this.countDown = countDown;
        }
    
        @Override
        public void run() {
            if(countDown.getCount() != 1){
                try {
                    countDown.await(3000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("俺是测试,俺是保证产品质量的");
            countDown.countDown();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1. 按指定步骤执行。
        public static void main(String[] args) {
    
            CountDownLatch countDownLatch = new CountDownLatch(4);
            // UI设计
            UI ui = new UI(countDownLatch);
            ui.start();
            // 产品经理
            ProductManager productManager = new ProductManager(countDownLatch);
            productManager.start();
            // 开发
            Developer developer = new Developer(countDownLatch);
            developer.start();
            // 测试
            Test test = new Test(countDownLatch);
            test.start();
            //
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("产品可以上线了");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 结果。
    俺是产品经理,俺是提需求的
    俺是设计,俺是设计界面的
    俺是开发,俺是干活的
    俺是测试,俺是保证产品质量的
    产品可以上线了
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总结

    CountDownLatch强调是其他任务执行完后,再执行指定任务,其他任务的执行顺序无法保证,当然可以多用几个CountDownLatch,也可以使用join()。
    join可以保证线程按顺序执行,即使线程睡眠。

          try {
                productManager.start();
                productManager.join();
                ui.start();
                ui.join();
                developer.start();
                developer.join();
                test.start();
                test.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行结果是一样的。
    CountDownLatch中线程睡眠,执行顺序就不一样了。
    ProductManager 睡眠1000ms。

    public class ProductManager extends Thread {
        private CountDownLatch countDown;
    
        public ProductManager(CountDownLatch countDown) {
            this.countDown = countDown;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("俺是产品经理,俺是提需求的");
            countDown.countDown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Developer睡眠3000ms。
    执行:

            CountDownLatch countDownLatch = new CountDownLatch(4);
            // UI设计
            UI ui = new UI(countDownLatch);
            // 产品经理
            ProductManager productManager = new ProductManager(countDownLatch);
            // 开发
            Developer developer = new Developer(countDownLatch);
            // 测试
            Test test = new Test(countDownLatch);
    
            productManager.start();
            ui.start();
            developer.start();
            test.start();
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("产品可以上线了");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    结果:

    俺是设计,俺是设计界面的
    俺是测试,俺是保证产品质量的
    俺是产品经理,俺是提需求的
    俺是开发,俺是干活的
    产品可以上线了
    
    • 1
    • 2
    • 3
    • 4
    • 5

    CountDownLatch只能是只触发一次的事件。若是需要多次触发,就需要使用CyclicBarrier。

  • 相关阅读:
    JVM主要组成部分及其作用
    7款三维地球软件/框架:Google Earth SkylineGlobe,Cesium等
    传统方式连接数据库的弊端和数据库连接池原理
    暑假好看的日剧来啦~~
    四、K8S之Deployment
    PHP项目学习笔记-萤火商城https://www.yiovo.com/doc
    解决 Github port 443 : Timed out
    Redis安装-Docker
    Vue08/Vue 生命周期钩子函数( Vue生命周期11个阶段 )应用场景
    mpu6050姿态解算与卡尔曼滤波(5)可应用于51单片机的卡尔曼滤波器
  • 原文地址:https://blog.csdn.net/qq_34202054/article/details/123663729