一次触发线程池拒绝策略问题的排查

一次触发线程池拒绝策略问题的排查

这个问题的原因是团队中的同事排查出来的,本人觉得这个问题很经典,所以记录一下

线上偶尔会出现线程池拒绝策略触发的告警

每次出现告警都会查看数据库、JVM等监控,系统都是比较平稳的,没有出现请求暴涨的情况,所以认为大概率是线程池配置的问题

分析过程

线程池参数有很多,但最核心的是三个corePoolSize、maximumPoolSize、workQueuequeueCapacity,三者的关系如下

系统通过JDK原生线程池ThreadPoolTaskExecutor设置线程池参数,细细看了这个类的代码,corePoolSize、maxPoolSize、keepAliveSeconds等参数都是正常的设置(set),只有queueCapacity参数做了一些判断,代码如下

如果阻塞队列容量大于0,阻塞队列使用LinkedBlockingQueue,等于0,使用SynchronousQueue

于是做个测试,看看是不是这里导致的

测试代码如下,如果触发了线程池拒绝策略,打印出来

理论上核心线程数有10个,一组执行完,另一组还可以使用核心线程执行,是不需要触发非核心线程的,结果出乎我的意料

queueCapacity等于1的情况

queueCapacity等于0的情况

显然,使用LinkedBlockingQueue,线程复用率不高,导致触发了线程池拒绝策略

那么问题来了,为什么LinkedBlockingQueue线程复用率不高,google搜索了一下

千篇一律都是这种类型的文章,只有结论,没有说为什么,所以只能去看源码

线程池源码

线程池提交任务的代码如下

这段代码跟文章开头那张图是完美对应的,核心代码在于 workQueue.offer(command),因为入队失败,才会 addWorker(command, false)创建非核心线程

所以为什么SynchronousQueue会入队成功,LinkedBlockingQueue会入队失败,只能看两个队列的源码,比较一下,下面简单说说两者的源码

SynchronousQueue源码

SynchronousQueue代码还是蛮复杂的,有公平非公平两种模式,默认是非公平,如下图

  1. SynchronousQueue每个节点有三个状态,分别是未匹配的消费者、未匹配的生产者、正在匹配另一个生产者或消费者
  2. 当队列为空时,生产者或者消费者会直接进入栈中,自旋或者阻塞等待生产者或者消费者匹配
  3. 当栈中有生产者,消费者进入会去匹配该生产者,或者当栈中有消费者,生产者进入会进行匹配,匹配完成一起出栈
  4. 当栈中有生产者与消费者正在匹配,又进来了一个生产者或者消费者线程,它会协助两者匹配

看上是不是很懵,其实我一开始也很懵,juc包的代码是很难理解的,下面是详细的代码

LinkedBlockingQueue 源码解析

我的一点猜想

  1. LinkedBlockingQueue存取节点使用锁进行了互斥,性能没有SynchronousQueue好,所以同样的数据SynchronousQueue处理起来更快
  2. SynchronousQueue支持多线程协作栈中数据,可以充分利用多线程的好处,不像LinkedBlockingQueue,队列到达上限,直接返回false,任务只能创建非核心线程

由于本人水平有限,无法在多线程的环境下验证自己的猜想,期待大佬指点一二

参考文档

tech.meituan.com/2020/04/02/...

相关推荐
知其然亦知其所以然2 分钟前
Redis 命中率 99%,数据库却 100% CPU,是谁在捣鬼
redis·后端·面试
天天摸鱼的java工程师4 分钟前
后端密码存储优化:BCrypt 与 Argon2 加密方案对比
java·后端
雨中飘荡的记忆5 分钟前
Vavr:让Java拥抱函数式编程的利器
java
沈千秋.7 分钟前
xss.pwnfunction.com闯关(1~6)
java·前端·xss
关于不上作者榜就原神启动那件事12 分钟前
Spring Data Redis 使用详解
java·redis·spring
鱼鱼块13 分钟前
React 组件通信实战:从 props 入门到父子协作闭环
前端·react.js·面试
invicinble18 分钟前
java集合类(二)--map
java·开发语言·python
王中阳Go18 分钟前
全面解析Go泛型:从1.18到最新版本的演进与实践
后端·面试·go
Mr-Wanter24 分钟前
搭建局域网时间同步服务器
java·运维·服务器
代码笔耕24 分钟前
我们这样设计消息中心,解决了业务反复折腾的顽疾
java·后端·架构