CountDownLatch踩过的坑[通俗易懂]

CountDownLatch踩过的坑[通俗易懂]线上生产环境dubbo报线程池满了,经过一天排查锁定在开三个线程计算最后合并数据的步骤中。简单描述下该步骤线程开三个调用三个不同的方法使用countdownlatch计数器等待三个方法全部执行完成合并数据。但是由于其中一个方法调用第三方接口,接口返回异常导致转换数据报错。导致其中一个方法未正常完成。举例demo:publicstaticvoidmain(String[]a…

大家好,又见面了,我是你们的朋友全栈君。

线上生产环境dubbo报线程池满了,经过一天排查锁定在开三个线程计算最后合并数据的步骤中。简单描述下该步骤线程开三个 调用三个不同的方法 使用countdownlatch 计数器等待三个方法全部执行完成 合并数据。但是由于其中一个方法调用第三方接口,接口返回异常导致转换数据报错。导致其中一个方法未正常完成。

举例demo:

public static void main(String[] args) {
    ExecutorService executorService =Executors.newFixedThreadPool(3);
    CountDownLatch cdl = new CountDownLatch(3);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            /*try {
                function1();
            } catch (Exception e) {
                //异常处理
                e.printStackTrace();
            }
            finally {
                cdl.countDown();
            }*/
            function1();
        }
    });

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            function2();
            cdl.countDown();
        }
    });

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            function3();
            cdl.countDown();
        }
    });


    try {
        cdl.await();
        //cdl.await(20,TimeUnit.SECONDS);
        System.out.println("三个执行线程结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
        System.out.println("执行线程异常");
    }
    finally {
        executorService.shutdown();
        System.out.println("执行线程关闭");
    }


}

private static void function1(){
    int i = 10/0;
    System.out.println("方法一");
}

private static void function2(){
    System.out.println("方法二");
}

private static void function3(){
    System.out.println("方法三");
}

CountDownLatch踩过的坑[通俗易懂]

方法一抛出异常,但是没有做异常处理导致不会执行线程关闭步骤,是不是和想象中不一样,一开始我也是懵,看了一下CountDownLatch原理就很好理解了,

“CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。”【1】

举一个现实中例子就是:CountDownLatch 就像跑步比赛中的裁判,三个方法就是就是三位运动员,运动员2,3都已经到达终点,但是运动员1摔倒了,动不了。裁判员只看到两位运动员到达终点不能宣布比赛结束,所以一直等。。。 

就像这样的场景导致线上service执行线程阻塞,接口调用次数累计导致dubbo线程满了(跟dubbo线程模型有关,有时间具体谈谈这一点)

知道原因了,就要考虑怎么修改

比赛不能无限期等,所以比赛必须在有限时间内结束,所以使用

public boolean await(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

线程内部也许要增加异常处理

executorService.execute(new Runnable() {
    @Override
    public void run() {
        try {
            function1();
        } catch (Exception e) {
            //异常处理
            e.printStackTrace();
        }
        finally {
            cdl.countDown();
        }
       // function1();
    }
});

修改后demo

public static void main(String[] args) {
    ExecutorService executorService =Executors.newFixedThreadPool(3);
    CountDownLatch cdl = new CountDownLatch(3);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            try {
                function1();
            } catch (Exception e) {
                //异常处理
                e.printStackTrace();
            }
            finally {
                cdl.countDown();
            }
           // function1();
        }
    });

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            function2();
            cdl.countDown();
        }
    });

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            function3();
            cdl.countDown();
        }
    });


    try {
       // cdl.await();
        cdl.await(20,TimeUnit.SECONDS);
        System.out.println("三个执行线程结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
        System.out.println("执行线程异常");
    }
    finally {
        executorService.shutdown();
        System.out.println("执行线程关闭");
    }


}

private static void function1(){
    int i = 10/0;
    System.out.println("方法一");
}

private static void function2(){
    System.out.println("方法二");
}

private static void function3(){
    System.out.println("方法三");
}

执行结果

CountDownLatch踩过的坑[通俗易懂]

大家结合自己的现实使用修改,爬过了使用坑,记录下分享下 ,希望能对别人有用

【1】参考https://www.jianshu.com/p/4b6fbdf5a08f

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158775.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 移动端开发遇到的一些兼容性问题及其整理「建议收藏」

    移动端开发遇到的一些兼容性问题及其整理「建议收藏」IOS手机测试时会发现加了margin-bottom的属性无效。解决:替换为padding-bottom或者放个空盒子有高度宽度占位即可。IOS手机的输入框出现未知的内阴影。解决:input:{-webkit-appearance:none;}控制手机上方的标题:document.title;…

    2022年6月24日
    41
  • 基于量化交易回测的金融股票案例基础知识[通俗易懂]

    基于量化交易回测的金融股票案例基础知识[通俗易懂]1量化交易定义量化交易是指以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据中海选出能带来超额收益的多种“大概率”事件以制定策略。它极大的降低了市场波动给投资者情绪带来的影响,避免在市场极度狂热或者悲观的情况下做出非理性的投资决策。2量化交易分类趋势性交易:适合一些主观交易的高手,用技术性指标作为辅助工具在市场中如鱼得水的,但如果只用各种技术指标或指标组合作为核心算法…

    2022年5月8日
    57
  • python数字推盘_从零开始学编程做游戏:一个文科生策划的14周

    python数字推盘_从零开始学编程做游戏:一个文科生策划的14周点击”humansflee”按钮则人类移动一回合,点击”zombiesstalk”按钮则僵尸移动一回合。它们采取的寻路策略都是广度优先搜索。游戏不会结束,你可以在这个沙盒中给自己安排胜利条件。布置各种各样的场面看着它们行动,也还能支撑个半小时的乐趣,是到目前为止制作的可玩性最强的游戏……同样的,这个游戏也是一个具有充分扩展性的游戏。感染者会不会转化成僵尸?人类能不能拿到武器反击僵尸?僵…

    2025年6月22日
    5
  • 海洋测绘 知识点 详细

    海洋测绘 知识点 详细一、第一章海洋测绘概述第一节、海洋测绘的发展第二节、世界海洋新格局1.海洋法公约的一些主要概念与定义:(1)内海:也叫内水,指的是领海基线以内的水域,国家对其享有完全排他性主权(2)领海:领海向外延伸12海里的区域(1海里(nmi)=1.852千米(km),沿海国主权管辖下与其海岸或内水相邻的一定宽度的海域,是国家领土的组成部分(3)毗邻区:毗邻国家领海,并在领海外一定宽度的,供沿…

    2022年6月6日
    61
  • nginx转发http请求

    nginx转发http请求原路径:http://source.server.com/callback/test/test?username=xx转发到:http://10.1.9.1:8088/callback/test/test?username=xx配置如下:server{listen80;server_namesource.server.com;…

    2022年10月19日
    2
  • ts 视频下载[通俗易懂]

    ts 视频下载[通俗易懂]importurllib.requestimportrequests,os,threadingfromCrypto.CipherimportAESfromsrc.Pacho.moviePa.tsdownloadimportaes_decodeclassm3u8down(object):def__init__(self,url,listheaders,dicheaders):self.url=url#这里的url是index.m3.

    2022年7月18日
    20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号