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

发现:

线上一个使用线程池处理任务的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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tomcat处理HTTP同步请求的过程大致如下: 1. 客户端发送HTTP请求到Tomcat服务器。 2. Tomcat服务器接收并解析请求,提取出请求的HTTP方法、URL、头部信息以及请求体等。 3. Tomcat根据URL寻找对应的Servlet,并将请求交给该Servlet处理。 4. Servlet进行请求处理,可能包括验证用户身份、处理业务逻辑、访问数据库等。 5. Servlet生成响应数据并封装成HTTP响应对象。 6. Tomcat将HTTP响应对象返回给客户端。 7. 客户端接收到响应,解析响应头部信息,根据状态码判断请求是否成功。 8. 如果请求成功,客户端根据响应的内容进行相应的处理,可能包括渲染页面、显示数据等。 在上述过程中,Tomcat通过监听和接收HTTP请求,并调用相应的Servlet来处理请求。Servlet是Tomcat的核心组件,它负责接收HTTP请求处理业务逻辑以及生成HTTP响应。Tomcat作为一个基于Java的Web服务器,能够处理来自客户端的多线程请求,并使用复用机制以提高性能。同时,Tomcat还提供连接器(Connector)来接收和处理HTTP请求,利用线程池来管理和复用线程资源,提高请求处理效率。 总的来说,Tomcat处理HTTP同步请求的过程包括接收和解析请求、调用相应的Servlet进行处理、生成HTTP响应并返回给客户端。这个过程是基于Java Web技术的核心流程,通过合理的配置和优化,能够提供高效稳定的Web服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值