✅动态线程池的原理是什么?
典型回答
所谓动态线程池,就是可以在运行时根据系统负载自动调整线程数量,相比传统固定线程池,它能更智能地应对流量波动,优化资源利用。
这里面有3个关键点:
1、运行时
2、根据系统负载
3、调整线程数量
这里面的第一点和第三点比较好理解,也很好实现,比如我们Java中的**ThreadPoolExecutor**来说,他提供了可以在运行时调整线程数量的方法,分别可以用**setCorePoolSize()**、**setMaximumPoolSize()**来调整核心线程数和最大线程数,调用之后立即生效。(只是数量生效,并不一定会立即创建这么多线程,真的用到才会再创建)
除了线程数量,其实有时候还可能调整其他的东西,比如线程池中的队列的容量,这里可以用ResizableCapacityQueue来作为队列,这样就可以运行期对它进行调整了。
那另外一个“根据系统负载”就不好理解了。想要根据系统负载作动态调整,那么首先得知道负载是什么情况,这就需要涉及到监控指标的采集,需要能采集到这些指标才行,具体哪些指标呢?
我认为比较关键的是下面这几个:
- 任务队列饱和度(当前队列大小 / 最大容量)
- 线程活跃度(活跃线程数 / 总线程数)
- 任务处理延迟(任务平均执行时间/排队时间)
- 系统资源指标(CPU利用率、内存使用率、load等)
怎么采集监控指标
这个其实有很多办法,比如基于日志采集、比较简单,就是定时的调一下线程池的查询线程数、查询队列容量、队列大小等等的方法。至于机器上的其他的指标,比如load ,cpu这些也可以考成熟的采集工具,比如Prometheus,很多动态线程池也支持用Prometheus来做监控。(在我的数藏项目课中有演示过如果基于prometheus来配置线程池的监控以及动态调整)
什么时候提高线程数?
什么时候可以提升线程数?
那肯定是线程数不够了, 并且提高也不会对系统造成影响的情况下。
什么时候可以认为线程数不够了?
任务队列快满了,比如容量的80%都被占用了,说明很多任务在堆积了。
什么时候可以认为不会对系统造成影响?
那就是当CPU的利用率、Load处于一个正常水平的时候,比如Cpu利用率在70%以下,Load在0.75以下(这是单核的指标,如果是多核要乘以对应的核数)。
那么也就是说,当任务队列增长到占了容量的80%,并且当前CPU利用率Cpu利用率在70%以下,Load在0.75以下,可以提升线程数。
什么时候减小线程数
为什么要减小线程数?
因为线程数如果过多的话,会导致大量的上下文切换,100个任务,5个线程执行,和10个线程执行,上下文切换的次数肯定不一样。
什么时候减小线程数?
那肯定是用不上那么多线程的时候,比如当前空闲线程已经超过了50%,那么就可以减少线程池中的线程数量了。
其他调整
一些成熟的动态线程池框架,比如dynamicTp,不仅支持线程数调整,还支持队列容量和拒绝策略的调整。但是一般改的都不多。