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

原文地址:https://www.cnblogs.com/zhaiyt/p/9897196.html

时间: 2024-08-02 19:53:14

JDK线程池的拒绝策略的相关文章

Java线程池的拒绝策略

一.简介 jdk1.5 版本新增了JUC并发编程包,大大的简化了传统的多线程开发.前面文章中介绍了线程池的使用,链接地址:https://www.cnblogs.com/eric-fang/p/9004020.html Java线程池,是典型的池化思想的产物,类似的还有数据库的连接池.redis的连接池等.池化思想,就是在初始的时候去申请资源,创建一批可使用的连接,这样在使用的时候,就不必再进行创建连接信息的开销了.举个生活中鲜明的例子,在去著名洋快餐某基或者某劳的时候,配餐人员是字节从一个中间

SimpleThreadPool给线程池增加拒绝策略和停止方法

给线程池增加拒绝策略和停止方法 package com.dwz.concurrency.chapter13; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class SimpleThreadPool3 { private final int size; private final int queueSize; private final static int DEFA

JAVA线程池的拒绝策略有哪几种?

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略: AbortPolicy:丢弃任务并抛出RejectedExecutionException异常. 这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态.如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现. DiscardPolicy:丢弃任务,但是不抛出异常. 如果线程队

Java - &quot;JUC线程池&quot; 线程状态与拒绝策略源码分析

Java多线程系列--"JUC线程池"04之 线程池原理(三) 本章介绍线程池的生命周期.在"Java多线程系列--"基础篇"01之 基本概念"中,我们介绍过,线程有5种状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态.线程池也有5种状态:然而,线程池不同于线程,线程池的5种状态是:Running, SHUTDOWN, STOP, TIDYING, TERMINATED. 线程池状态定义代码如下: private final AtomicI

java并发:线程池、饱和策略、定制、扩展

一.序言 当我们需要使用线程的时候,我们可以随时新建一个线程,这样实现起来非常简便,但在某些场景下存在缺陷:如果需要同时执行多个任务(即并发的线程数量很多),频繁地创建线程会降低系统的效率,因为创建和销毁线程均需要一定的时间.线程池可以使线程得到复用,所谓线程复用就是线程在执行完一个任务后并不被销毁,该线程可以继续执行其他的任务. 二.Executors提供的线程池 Executors是线程的工厂类,也可以说是一个线程池工具类,Executors提供的线程都是通过参数设置来实现不同的线程池机制.

JDK线程池

简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力,但频繁的创建线程的开销是很大的,那么如何来减少这部分的开销了,那么就要考虑使用线程池了.线程池就是一个线程的容器,每次只执行额定数量的线程,线程池就是用来管理这些额定数量的线程 线程池相关类结构图 ExecutorService继承了Executor接口 Executor接口中的定义: public interface Executor { /** * Executes the

线程池队列饱和策略

1.当一个有限队列充满后,线程池的饱和策略开始起作用. 2.ThreadPoolExecutor的饱和策略通过调用setRejectedExecutionHandler来修改.不同的饱和策略如下: 1)AbortPolicy:中止,executor抛出未检查RejectedExecutionException,调用者捕获这个异常,然后自己编写能满足自己需求的处理代码. 2)DiscardRunsPolicy:遗弃最旧的,选择丢弃的任务,是本应接下来就执行的任务. 3)DiscardPolicy:

jdk线程池主要原理

本文转自:http://blog.csdn.net/linchengzhi/article/details/7567397 正常创建一个线程的时候,我们是这样的:new thread(Runnable实现类).这里,thread是线程,Runnable实现类是业务逻辑,这样线程和业务逻辑紧紧绑定在一起. 采用线程池来处理的时候,我们动态生成若干个线程存于池中,但是这些线程要执行那些业务逻辑是不知道的,由于业务逻辑个数和具体的逻辑需要用户来指定,这些是变化的,我们需要自己编写并存于linkedLi

线程池工作队列饱和策略

线程池工作队列饱和策略 Java线程池会将提交的任务先置于工作队列中,在从工作队列中获取(SynchronousQueue直接由生产者提交给工作线程). 那么工作队列就有两种实现策略:无界队列和有界队列. 无界队列不存在饱和的问题,但是其问题是当请求持续高负载的话,任务会无脑的加入工作队列,那么很可能导致内存等资源溢出或者耗尽. 而有界队列不会带来高负载导致的内存耗尽的问题,但是有引发工作队列已满情况下,新提交的任务如何管理的难题,这就是线程池工作队列饱和策略要解决的问题. 无界队列不存在饱和的