• JDK线程池的拒绝策略


    关于新疆服务请求未带入来话原因的问题

           经核查,该问题是由于立单接口内部没有成功调用接续的 “更新来电原因接口”导致的,接续测更新来电原因接口编码:NGCCT_UPDATESRFLAG_PUT ,立单接口调用代码如下:

    final Map<String, Object> paramsMap = outputObject.getBean();
    paramsMap.put("provCode", provCode);
    paramsMap.put("tenantId", MapUtils.getString(inputObject.getParams(), "tenantId"));
    TaskEngine.getInstance().submit(new Runnable() {
       @Override
       public void run() {
          callContactRel(paramsMap);[zhai1] 
          backWriteWrkfm(paramsMap);
       }
    });

    立单接口中使用起多线程异步调用方式,更新来电原因方法内部记录日志,由于线程内部日志无法在火眼系统查看,当出现该问题时,

    1.多次找在线运维人员查看主机上的日志,均未发现更新来话原因方法内部记录的日志;

    2.登陆csf平台查询该接口的调用记录,根据出现问题的流水号均未查到相关调用记录;

    3.核查调用更新来电原因方法内部catch中如表的错误记录,也未发现问题;

    根据火眼上上下文日志,确定程序一定运行到了启动多线程的地方,遂怀疑线程池的问题,

    该处启用多线程使用的是 TaskEngine工具提供的获取线程池,使用池中资源执行任务。

    经核查TaskEngine类发现该类在初始化的时候会创建一个线程池,核心线程数为1,最大线程数为30的线程池,代码如下:

    private static TaskEngine instance = new TaskEngine();
    public static TaskEngine getInstance() {
    
        return instance;
    
    }
    private TaskEngine() {
    
        executor = new ThreadPoolExecutor(1, 30,180L,
    
                TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {
    
            final AtomicInteger threadNumber = new AtomicInteger(1);
    
    
    
            public Thread newThread(Runnable runnable) {
    
                // Use our own naming scheme for the threads.
    
                Thread thread = new Thread(Thread.currentThread().getThreadGroup(), runnable,
    
                        "TaskEngine-pool-" + threadNumber.getAndIncrement(), 0);
    
                // Make workers daemon threads.
    
                thread.setDaemon(true);
    
                if (thread.getPriority() != Thread.NORM_PRIORITY) {
    
                    thread.setPriority(Thread.NORM_PRIORITY);
    
                }
                return thread;
            }
        });
    }

    该线程池构造时尚未指明 拒绝策略 [zhai2] 因此会默认使用 AbortPolicy

    JDK提供的ThreadPoolExecutor 线程池有四种 拒绝策略:

    AbortPolicy 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。

    CallerRunsPolicy 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。

    DiscardOldestPolicy 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。

    DiscardPolicy 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

    工程中使用的默认的策略,会不会存在一种情况,在某一个时刻,使用TaskEngine类获取线程池来执行任务时,30个线程同时被使用,导致创建任务数大于最大线程数的限制,该任务将无法被成功执行。

    Demo验证:

    1.使用与项目中相同的线程池执行数据入库操作,模拟设置最大线程数10,核心线程1个,拒绝策略默认:

    @RequestMapping(value = "/testThread")
    
    public String testThread(){
    
        final CommonCfgCode commonCfgCode = new CommonCfgCode();
    
        commonCfgCode.setCodeTypeCd("Thread");
    
        TaskEngine taskEngine = TaskEngine.getInstance();
    
        for(int i=0;i<100;i++){
    
            taskEngine.submit(new Runnable() {
    
                @Override
    
                public void run() {
    
                    testService.save(commonCfgCode);
    
                }
    
            });
    
        }
    
        return "SUCCESS";
    
    }

    循环执行100个任务进行如表操作抛出:

    java.util.concurrent.RejectedExecutionException异常,与该策略描述一致。

    查看如表数据:仅如表10条数据;

     

    2.将拒绝策略修改为:CallerRunsPolicy 其它不变;

    无报错,查询数据:如表100条;(110条中包含使用默认拒绝抛异常策略如表的10条)

     

    Demo git路径:https://git.lug.ustc.edu.cn/zhaiyt/mylife.git

    由于该问题仅在新疆出现,出现的场景无法预知,请各位评审是否可以修改项目中TaskEngine类。


     [zhai1]调用接续接口更新来话原因方法

     [zhai2]线程池的拒绝策略,是指当任务添加到线程池中被拒绝,而采取的处理措施。当任务添加到线程池中之所以被拒绝,可能是由于:第一,线程池异常关闭。第二,任务数量超过线程池的最大限制

  • 相关阅读:
    转:Spark User Defined Aggregate Function (UDAF) using Java
    同步类容器和并发类容器
    线程间通信
    线程安全
    浅入tomcat
    PLSQL操作excel
    Eclipse中使用Maven创建web项目
    PLSQL数据库操作(excel)
    Python学习-列表深浅拷贝
    Python学习-列表元组字典操作
  • 原文地址:https://www.cnblogs.com/zhaiyt/p/9897196.html
Copyright © 2020-2023  润新知