JavaKNOWJava

线程池的几个灵魂拷问(二)

2020-10-08  本文已影响0人  千淘萬漉

线程池虽然在并发编程里很强大,但线程池使用面临的核心的问题在于:线程池的参数并不好配置。一方面线程池的运行机制不是很好理解,配置合理需要强依赖开发人员的个人经验和知识;另一方面,线程池执行的情况和任务类型相关性较大,IO密集型和CPU密集型的任务运行起来的情况差异非常大,这导致业界并没有一些成熟的经验策略帮助开发人员参考。

美团方案

比如网上流传的比较多的一个策略:

CPU密集型的为什么要+1呢?《Java并发编程实战》给出的原因是:即使当计算(CPU)密集型的线程偶尔由于页缺失故障或者其他原因而暂停时,这个“额外”的线程也能确保 CPU 的时钟周期不会被浪费。

这里先来看看美团帮我们总结的现在业界的一些线程池调参方案:

cpu参数方案

第一套方案是并发编程实战给出的,明显太理论化了,和实际业务想去甚远!

N(threads) = N(Cpu个数)*U(cpu的使用率)*(1+ 等待时间/计算时间)

第二套方案就没有考虑多个业务线程池的情况。
第三套方案的用到了TPS来参与计算,但是这也是流量恒定情况下算出来的,真实情况往往比较随机。

有啥比较好的办法吗?——那就是:线程池参数动态化,采用这种方案最好就是用这么一个办法来做:

为什么能做到动态修改线程池参数呢?这是因为JDK本身就提供api方法支持动态的修改:

设置核心线程数的大小

至于如何在运行时状态实时查看,这里也有一个办法:用户基于JDK原生线程池ThreadPoolExecutor提供的几个public的getter方法,可以读取到当前线程池的运行状态以及参数:

线程池的运行时状态

用户基于这个功能可以了解线程池的实时状态,比如当前有多少个工作线程,执行了多少个任务,队列中等待的任务数等等。

Netty进阶指南给出来的方案

在Netty服务编写的过程中,也要涉及到两个线程池的参数配置,尤其是IO线程池的配置,这里书中也给了一套经验方案来针对线程的监控情况,可以参考:
同样的先用CPU核数*2,看看是否存在瓶颈,运行时的监控则用比较土的办法了:

如果多次采集都发现有这堆信息的话,说明此时此刻的IO线程比较空闲,无需调整;但是如果一直在read或者write的执行处,则说明IO较为繁忙,可以适当的去调大NioEventLoop线程的个数来提升网络的读写性能。但是这边线程数的改动就不是动态化的了,服务启动后指定的线程数就不能再修改了。

参考文章


1、Java线程池实现原理及其在美团业务中的实践
2、微信文章:如何设置线程池参数?美团给出了一个让面试官虎躯一震的回答。

上一篇下一篇

猜你喜欢

热点阅读