当前位置:网站首页>线程池的创建及参数设置详解
线程池的创建及参数设置详解
2022-08-05 06:43:00 【李孛欢】
一. 常见线程池
线程池的创建方法主要有两类,第一是通过Executors 创建线程池,第二是通过 ThreadPoolExecutor 创建线程池。
首先我们来看通过Executors 创建的线程池是什么样的
1. Executors.newFixedThreadPool:创建⼀个固定大小的线程池,特点是核心线程数等于最大线程数,可控制并发的线程数,超出的线程会在有界队列中等待;
2. Executors.newCachedThreadPool:创建一个可缓存的线程池,特点是核心线程数为0,队列采用了SynchronousQueue,没有线程来take,任务不能put进去,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;
3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;
5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执行延迟任务的线程池;
6. Executors.newWorkStealingPool:创建⼀个抢占式执行的线程池(任务执行顺序不确定)【JDK1.8 添加】。
一般不推荐使用Executors 的方式去创建线程池,而是通过ThreadPoolExecutor 根据项目实际去设置参数创建线程池,下面我们主要分析一下线程池核心参数的设置。
二. 线程池参数设置详解
在这个问题展开前,我们先来了解一下压测,即压力测试,是确立系统稳定性的一种测试方法,通常在系统正常运作范围之外进行,以考察其功能极限和和可能存在的隐患。
压测的目的就是通过模拟真实用户的行为,测算出机器的性能(单台机器的 QPS、TPS),从而推算出系统在承受指定用户数(100 W)时,需要多少机器能支撑得住。因此在进行压测时一定要事先设定压测目标值,这个值不能太小,也不能太大,按照目前业务预估的增长量来做一个合理的评估。
压测的一些名词解释:

首先,我们线程池的参数设置最后必须要通过压测来确定,需要符合我们的业务需求。那么我们如何开始进行压测参数配置的,也就是说压测前我们线程池的参数应该如何选取,这个问题需要分情况去讨论:
情况一:当前的线程池可以占用我们服务器的所有资源
基于先辈程序员的理论基础和实践,进行线程池的参数合理调整,然后经过压测,最终确定我们的参数。
例如:
- 计算密集型:CPU核数 + 1
- IO密集型:2 * CPU核数 or CPU利用率 * (1 + 等待时间 / 计算时间)* CPU核心数
情况二:当前线程池不可以使用机器的所有资源
由于我们目前机器不是单机部署的,分布式部署的情况,一个服务多个接口的情况,比如两个重要接口,三个可降级的接口,在这个场景下比如说一个重要接口里面需要创建一个线程池来提高单接口的处理速度,那么这个时候怎么去设置参数。也就是说,我这个线程池不能获得服务器的所有资源。
具体案例:需要拿到该服务各个接口的访问比例,比如4个接口,各个比例为 2 : 3 :1 : 1
两个核心服务接口(承载60%+)
A. 需要创建线程池,提高单接口处理速度,这时候怎么设置线程池参数(最核心的三个参数:最大线程数,核心线程数以及阻塞队列的选择)
- 第一个接口访问量占用 1 / 4:因此分配1/4的资源
- 第二个接口访问比例 3 / 8:因此分配 3/8 的资源
- 接下来确定最大线程数(贴合实际):不能随意的将一个线程池线程数加大,这样的话会导致其他接口不能雨露均沾,具体情况考虑CPU核数,所有接口的最大QPS,和本机活跃的live的线程数。拿到这些数据后再通过上述访问比例去分配资源。
- 核心线程数:初次压测设置成为一样大,测试最大并发访问的情况。撑得住,调小核心线程数。撑不住,我们还有一个阻塞队列去调整,接下来去确定阻塞队列
- 不推荐无界队列:使用无界队列相当于干掉了最大线程数这个参数,违背了线程池的设计初衷,还有无限积压请求,最终导致OOM问题。推荐使用有界队列:不推荐直接使用Integer.max_value,而是模拟我们访问量最大的场景来确定,将高峰访问时段与我们压测进行匹配,具体参数设置:(这个时段的访问数量 减去 这个时段接口能处理的请求数量)* 150%,也就是用我们接口能处理请求后剩余的值适当提升50%作为我们有界队列的上限。
- 设置完后进行压测
B. 案例情况:如果按照上述条件调整了,还没达到预期怎么办?
- 已经达到最大线程数3/8了,那就调大队列的最大等待数(首先调整队列而不是线程数)。好处:不影响其他接口,当前线程只是等待,而不是不可用
- 如果,业务方不同意上述等待方案:优化当前接口代码,把并发性调整一下,调高。
- 线程数适当再调大一点,但是不能再多很多了,否则会影响其他接口
- 添加机器
案例情况:如果线程核数设置不合理,会产生什么问题?
- 接口线程池设置太小,接口异常请求数量增多:如果使用抛异常降级策略,将会导致有大量的异常日志。会造成接口熔断或者降级(非正常性质的),导致生产事故。
- 接口线程池设置太大:当前接口活得挺好,但是会挤兑其他接口的资源,其他接口没有足够的资源,导致系统接口积压,系统崩溃。
总结:
- 先按照接口请求比例设置占用最大线程数
- 按照压测情况,适当设置核心线程数
- 按照最大情况,留出一定的等待队列阈值
- 饱和策略:按照具体情况具体分析
边栏推荐
- 线程池的使用(结合Future/Callable使用)
- Redis
- 2022熔化焊接与热切割操作证考试题及模拟考试
- Flink学习11:flink程序并行度
- Invalid operator for data type.The operator is add and the type is text.
- 【Dynamic type detection Objective-C】
- 693. 行程排序
- HR:这样的简历我只看了5秒就扔了,软件测试简历模板想要的进。
- Shared memory + inotify mechanism to achieve multi-process low-latency data sharing
- Database table insert data
猜你喜欢
随机推荐
Falsely bamboo brother today and found a localization of API to use tools
MySQL: basic part
Hash these knowledge you should also know
对数据类型而言运算符无效。运算符为 add,类型为 text。
今天虚竹哥又发现了一款好用的国产化API工具
GAN generates anime avatar Pytorch
After the firewall iptable rule is enabled, the system network becomes slow
2022 crane driver (limited bridge crane) exam question bank and simulation test
Redis
The NDK compiler so libraries
UDP group (multi)cast
腾讯实习总结
【动态类型检测 Objective-C】
技术分析模式(十)头肩图案
protobuf is compiled against the associated .proto file
Modeling of the MAYA ship
Technical Analysis Patterns (11) How to Trade Head and Shoulders Patterns
日本卫生设备行业协会:日本温水喷淋马桶座出货量达1亿套
Promise (三) async/await
After working for 3 years, I recalled the comparison between the past and the present when I first started, and joked about my testing career









