欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用线程池仍同步处理请求问题

程序员文章站 2022-04-11 13:04:17
发现:线上一个使用线程池处理任务的RPC接口超时:@Resourceprivate ThreadPoolTaskExecutor threadPool;@Override public Response rpcMethod(Request request) throws TException { //这里使用匿名内部类方式创建Runnable类型的线程 threadPool.submit(() -> myMethod(request));}排查上面接口...

发现:

线上一个使用线程池处理任务的RPC接口超时:

@Resource
private ThreadPoolTaskExecutor threadPool;

@Override
    public Response rpcMethod(Request request) throws TException {
    	//这里使用匿名内部类方式创建Runnable类型的线程
    	 threadPool.submit(() -> myMethod(request));
	}

排查

上面接口在日志里显示耗时3s, 按理收到请求后就使用线程池中的其他线程处理了,没有等待返回结果,接口应该很快,这里并没有使用Callable类型获取Future结果,所以理论上不会发生阻塞。
排查trace日志,发现显示这次整个调用链将myMethod内部的调用都打印出来,时间也都算在rpcMethod内了,说明线程池没有起作用,同步处理的这次请求
使用线程池仍同步处理请求问题

原因

查看线程池配置如下:

 <!-- 多线程配置 -->
    <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 线程池的前缀 -->
        <property name="threadNamePrefix" value="myThread"/>
        <!-- 核心线程数 -->
        <property name="corePoolSize" value="5" />
        <!-- 最大线程数 -->
        <property name="maxPoolSize" value="10" />
        <!-- 队列最大长度-->
        <property name="queueCapacity" value="500" />
        <!-- 线程池维护线程所允许的空闲时间,默认为60s -->
        <property name="keepAliveSeconds" value="30" />
        <!-- 核心线程超时退出,默认为false -->
        <property name="allowCoreThreadTimeOut" value="true" />
        <!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        </property>
    </bean>

当时的并发请求量为1000,在线程池中的处理为:

  • 如果运行的线程少于corePoolSize-5,则创建新线程来处理任务,即使线程池中的其他线程是空闲的 (这里前5个请求被放进阻塞队列中)

  • 如果线程池中的线程数量大于等于corePoolSize-5 且小于 maximumPoolSize-10,则只有当workQueue-500 满时才创建新的线程去处理任务。 (这里同时到达的第6-506个请求被放进阻塞队列中)

  • 如果设置的corePoolSize 和 maximumPoolSize相同,则创建的线程池的大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理;

  • 如果workQueue已经满了,会创建新线程处理新请求 (这里第507个到512个请求新建了5个线程处理) 直到线程数到达maximumPoolSize-10, 512后面的请求,由于最大线程数和阻塞队列都有任务了,则通过handler所指定的策略来处理任务
    线程池任务的优先级:corePoolSize>queueCapacity>maxPoolSize
    配置里制定的策略为CallerRunsPolicy:使用线程调用者所在的线程来执行任务
    使用线程池仍同步处理请求问题
    线程池提供了4种策略:

  • AbortPolicy:直接抛出异常,这是默认策略;

  • CallerRunsPolicy:用调用者所在的线程来执行任务;

  • DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;

  • DiscardPolicy:直接丢弃任务;

参考:
ThreadPoolExecutor里面4种拒绝策略–CallerRunsPolicy
Java多线程-线程池ThreadPoolExecutor的submit返回值Future

本文地址:https://blog.csdn.net/weixin_42655186/article/details/107359954