• 记录一次线上环境线程池使用后未关闭的记录


          下午时候运维的同学给我说 某个服务,线程池达到了2000 但是一直未回收,他们那边开始频繁报警了。然后用jstat导出了一份文件:

       

       第一个线程池bing-master-order-1 占用了 1511个线程且未回收,第二个111 个。 

       刚开始自己也是一头雾水,看了下下面的 mysql/redis ,这个应该是线程池占用个数。但是第一个 是什么,找到项目 ,搜搜 bing-master-order 发现有下面的代码

       

                JSONObject jsonResult = JSONObject.parseObject(result);
                if (jsonResult.get(Constants.CODE) != null && jsonResult.getInteger(Constants.CODE) == 0) {
                    logger.info("子单绑定主单成功");
                    this.noticeAssign(orderNo);
                    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
                            new BasicThreadFactory.Builder().namingPattern("bing-master-order-%d").daemon(true).build());
                    Future<String> future = executorService.submit(new Callable<String>() {
                        @Override
                        public String call() throws Exception {
                            logger.info("=================异步处理开始============" + jsonResult.getJSONObject(Constants.DATA));
                            JSONObject jsonData = jsonResult.getJSONObject(Constants.DATA);
                            try {
                                if (jsonData != null && jsonData.get(Constants.MAIN_ORDER_NO) != null) {
                                    String newMainOrderNo = jsonData.getString("mainOrderNo");
                                    MainOrderInterCity queryMain = interService.queryMainOrder(newMainOrderNo);
                                    logger.info("========查询结果=======" + JSONObject.toJSONString(queryMain));
                                    int code = 0;
                                    if (queryMain != null && queryMain.getId() > 0) {
                                        code = interService.updateMainOrderState(newMainOrderNo, 1, dispatcherPhone);
                                    } else {
                                        MainOrderInterCity main = new MainOrderInterCity();
                                        main.setDriverId(driverId);
                                        main.setCreateTime(new Date());
                                        main.setUpdateTime(new Date());
                                        main.setMainName(routeName);
                                        main.setStatus(MainOrderInterCity.orderState.NOTSETOUT.getCode());
                                        main.setMainOrderNo(newMainOrderNo);
                                        main.setOpePhone(dispatcherPhone);
                                        main.setMainTime(crossCityStartTime);
                                        code = interService.addMainOrderNo(main);
                                    }
                                    if (code > 0) {
                                        logger.info("=========子单绑定主单成功=======");
                                        return String.valueOf(code);
                                    }
                                    return String.valueOf(code);
                                }
                            } catch (Exception e) {
                                logger.error("子单绑定异常=======" + e);
                                String newMainOrderNo = jsonData.getString("mainOrderNo");
                                MainOrderInterCity queryMain = interService.queryMainOrder(newMainOrderNo);
                                logger.info("补录子单绑定开始====" + JSONObject.toJSONString(queryMain));
                                if (queryMain != null && queryMain.getId() > 0) {
                                    int code = interService.updateMainOrderState(newMainOrderNo, 1, dispatcherPhone);
                                    if (code > 0) {
                                        logger.info("=====补录异常成功=====");
                                    }
                                }
                            }
                            return "=============子单绑定异常==========";
                        }
                    });
    
                    return AjaxResponse.success(null);
    
    
                } else {
                    logger.info("子单指派主单返回信息========" + jsonResult.toString());
                    return AjaxResponse.failMsg(jsonResult.getIntValue("code"), jsonResult.getString("msg"));
                }
    
            } 

            注意红色部分,点开.damon的源码

         

    /**
             * Sets the daemon flag for the new {@code BasicThreadFactory}. If this
             * flag is set to <b>true</b> the new thread factory will create daemon
             * threads.
             *
             * @param f the value of the daemon flag
             * @return a reference to this {@code Builder}
             */
            public Builder daemon(final boolean f) {
                daemonFlag = Boolean.valueOf(f);
                return this;
            }

       如果为属性设置为true,表示将会创建一个daemon 守护线程。众所周知,垃圾回收的jvm就是守护进程,当jvm都是守护进程时候 jvm会自动退出,所以设置后一直没有被回收。知道原因后修改为false。想了下自己当时为何设置为true而不是false,应该是使用阿里规范代码时候推荐的。之前自己用的是ExcuterService 创建的,但是阿里规约不推荐,原因如下:

    Executors各个方法的弊端:
    1)newFixedThreadPool和newSingleThreadExecutor:
      主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
    2)newCachedThreadPool和newScheduledThreadPool:
      主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

    当时就改成这样的了。没想到还是有风险,这次先这样给解决了,下次注意。

  • 相关阅读:
    Android自己定义组件系列【1】——自己定义View及ViewGroup
    LeetCode60:Permutation Sequence
    GitHub 优秀的 Android 开源项目
    view变化监听器ViewTreeObserver介绍
    android中ImageView的ScaleType属性
    Android静态图片人脸识别的完整demo(附完整源码)
    理解Android的手势识别
    Android浏览图片,点击放大至全屏效果
    Android中如何实现文件下载
    Android语音识别
  • 原文地址:https://www.cnblogs.com/thinkingandworkinghard/p/13476830.html
Copyright © 2020-2023  润新知