• java多线程CountDownLatch


    先上一个介绍:https://blog.csdn.net/shihuacai/article/details/8856370


    用视频https://www.bilibili.com/video/av81181427 中的一个例子来测试

        @Test
        public void countdownlatch ()throws InterruptedException {
            /*
                这个5不能循环,减到0了之后await作用就消失了
             */
            CountDownLatch countDownLatch=new CountDownLatch(5);
            for(int i=0;i<5;i++){
                new Thread(()->{
                    try{
                        Thread.sleep(new Double(Math.random()*3000).longValue());
                        System.out.println(Thread.currentThread().getName()+"玩家准备就绪");
                        countDownLatch.countDown();//计数点
                        System.out.println(Thread.currentThread().getName()+"玩家选择英雄");
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }).start();
            }
            countDownLatch.await();
           System.out.println(Thread.currentThread().getName()+"开始游戏");
            //Thread.sleep(3000);
        }
    

    输出为:

    Thread-0玩家准备就绪
    Thread-0玩家选择英雄
    Thread-2玩家准备就绪
    Thread-2玩家选择英雄
    Thread-4玩家准备就绪
    Thread-4玩家选择英雄
    Thread-3玩家准备就绪
    Thread-3玩家选择英雄
    Thread-1玩家准备就绪
    Thread-1玩家选择英雄
    main开始游戏
    

    实际上,CountDownLatch阻塞的是主线程而非子线程,这一点要弄清楚。子线程中countDownLatch.countDown();唯一的作用就是将CountDownLatch对象内部的计数器减一,它不能起到阻塞子线程的作用。唯一受到阻塞的是创建完子线程后执行countDownLatch.await();语句的父线程,只有CountDownLatch对象内的计数器减到0之后主线程才能继续执行,而这和子线程的执行无关。
    说明这一点最直观的方式是让CountDownLatch的初始参数比线程数小,我们把参数调成5,用10个线程。看看输出是什么:

    Thread-4玩家准备就绪
    Thread-4玩家选择英雄
    Thread-7玩家准备就绪
    Thread-7玩家选择英雄
    Thread-6玩家准备就绪
    Thread-6玩家选择英雄
    Thread-5玩家准备就绪
    Thread-5玩家选择英雄
    Thread-3玩家准备就绪
    Thread-3玩家选择英雄
    main开始游戏
    

    为什么只有5个子线程执行的结果,剩下的5个子线程去哪里了?别急,我们在主线程的代码末尾加一句sleep语句:

    		countDownLatch.await();
            System.out.println(Thread.currentThread().getName()+"开始游戏");
            Thread.sleep(3000);
    

    再次执行,结果是:

    Thread-7玩家准备就绪
    Thread-7玩家选择英雄
    Thread-9玩家准备就绪
    Thread-9玩家选择英雄
    Thread-2玩家准备就绪
    Thread-2玩家选择英雄
    Thread-6玩家准备就绪
    Thread-6玩家选择英雄
    Thread-0玩家准备就绪
    Thread-0玩家选择英雄
    main开始游戏
    Thread-5玩家准备就绪
    Thread-5玩家选择英雄
    Thread-4玩家准备就绪
    Thread-4玩家选择英雄
    Thread-1玩家准备就绪
    Thread-1玩家选择英雄
    Thread-3玩家准备就绪
    Thread-3玩家选择英雄
    Thread-8玩家准备就绪
    Thread-8玩家选择英雄
    

    可以看出,之前剩下五个子线程的内容输出不出来,是因为父线程执行完后函数返回了。但是我们知道,父线程和子线程是独立执行的。这是为什么?
    其实这是因为我使用的是Junit测试方法,而Junit不支持多线程而已,这个帖子就提到了这一点:在junit单元测试中,当创建了新线程后,单元测试并不会等待主线程下启动的新线程是否执行结束,只要主线程结束完成,单元测试就会关闭,导致主线程中启动的新线程不能顺利执行完.所以剩下的五个线程还没有执行就被销毁了。
    换成普通的main方法再试试:

    Thread-0玩家准备就绪
    Thread-0玩家选择英雄
    Thread-5玩家准备就绪
    Thread-5玩家选择英雄
    Thread-3玩家准备就绪
    Thread-3玩家选择英雄
    Thread-1玩家准备就绪
    Thread-1玩家选择英雄
    Thread-9玩家准备就绪
    Thread-9玩家选择英雄
    main开始游戏
    Thread-7玩家准备就绪
    Thread-7玩家选择英雄
    Thread-8玩家准备就绪
    Thread-8玩家选择英雄
    Thread-2玩家准备就绪
    Thread-2玩家选择英雄
    Thread-6玩家准备就绪
    Thread-6玩家选择英雄
    Thread-4玩家准备就绪
    Thread-4玩家选择英雄
    
    Process finished with exit code 0
    

    这回就正常了
    那如果CountDownLatch的初始参数比线程数大会发生什么,我们把参数调成10,用5个线程。

    Thread-2玩家准备就绪
    Thread-2玩家选择英雄
    Thread-1玩家准备就绪
    Thread-1玩家选择英雄
    Thread-0玩家准备就绪
    Thread-0玩家选择英雄
    Thread-4玩家准备就绪
    Thread-4玩家选择英雄
    Thread-3玩家准备就绪
    Thread-3玩家选择英雄
    

    实际上,虽然子线程都执行完了,程序还是不会停止的,因为CountDownLatch内的计数器不会被减到0,main线程一直处于阻塞状态。

  • 相关阅读:
    蓝桥杯 包子凑数(完全背包、裴蜀定理、赛瓦维斯特定理)
    AcWing 255. 第K小数主席树(可持久化线段树) 模板题
    HDU 1698 Just a Hook [线段树+区间修改为一个值+区间查询]
    POJ 3264 Balanced Lineup
    AcWing 1277. 维护序列
    HDU 3577 Fast Arrangement [线段树+区间修改+维护最大值]
    【学习笔记】权值线段树
    NOIP2017 小凯的疑惑 解题报告(赛瓦维斯特定理)
    k8s (kubenetes)集成runner 清明
    gitlab CIDI 构建环境优化 清明
  • 原文地址:https://www.cnblogs.com/jiading/p/12363051.html
Copyright © 2020-2023  润新知