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)
上一篇 2022年7月13日 下午10:16
下一篇 2022年7月13日 下午10:36


相关推荐

  • mysql databasemetadata_JDBC–使用DatabaseMetaData获取数据库信息

    mysql databasemetadata_JDBC–使用DatabaseMetaData获取数据库信息一些方法:getURL():返回一个String类对象,代表数据库的URL。getUserName():返回连接当前数据库管理系统的用户名。isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。getDatabaseProductName():返回数据库的产品名称。getDatabaseProductVersion():返回数据库的版本号。getDriverName():…

    2022年6月19日
    25
  • Arduino uno使用PCA9685模块实现16路舵机控制

    Arduino uno使用PCA9685模块实现16路舵机控制PCA9685 模块 PCA9685 是 16 路 12 位 PWM 信号发生器 可用于控制舵机 led 电机等设备 采用 I2C 通信 主机只需要 I2C 接口即可实现 16 路舵机控制 PCA9685 的 I2C 地址默认 0x40 如果需要改变地址 则需要将板上 A0 A5 焊通即可对应的 bit 置 1 此时地址为 0x40 A5 A0 这也意味着主机可以通过 I2C 地址控制 64 个 PCA9685 模块 从而实现最大 16 64 路舵机控制

    2026年3月18日
    2
  • jQuery -> bind / live / delegate 终结者 – on

    jQuery -> bind / live / delegate 终结者 – on

    2022年1月3日
    49
  • pycharm linux激活码_ubuntu python安装

    pycharm linux激活码_ubuntu python安装这里只介绍采用激活码激活的方法。如果是window系统则hosts文件路径为:C:\Windows\System32\drivers\etc,将0.0.0.0account.jetbrains.com添加到末尾即可。如下图所示:如果是linux系统 Linux的hosts文件路径为:/etc命令行输入:第一步:cd/etc第二步:sudogedithosts输…

    2022年8月28日
    4
  • 键盘 计算机代码,键盘钩子示例[通俗易懂]

    键盘 计算机代码,键盘钩子示例[通俗易懂]#region自定义事件//////Hooksthestart.///publicvoidHook_Start(){//安装键盘钩子if(hHook==0){KeyBoardHookProcedure=newHookProc(KeyBoardHookProc);hHook=SetWindowsHookEx(WH_KEYBOARD_LL,KeyBoardHookPr…

    2022年5月30日
    37
  • Web应用设置Context Path的方式

    Web应用设置Context Path的方式JettywarName INFjetty webxmlTomcat INFcontextxm 默认 contextxmlUR http hostname com contextPath servletPath pathInfoJett 如果没有 contextPath 则默认使用 root 上下文 root 上下文的路

    2026年3月17日
    2

发表回复

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

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