业务程序中如何设置线程数?

线程池线程数如何设置

在实际工作和面试中,线程池线程个数的设置是一个常见而又复杂的问题。我们通常在资料中找到一些经典的回答,例如判断任务是CPU密集型还是IO密集型,或者参考《Java并发编程实战》一书的建议:

1.判断任务是CPU密集型还是IO密集型(其中N表示CPU的核心数量):

  • CPU密集型,线程池大小设置为N+1。
  • IO密集型,线程池大小设置为2N+1。

然而,在实际业务中,任务往往涉及到复杂的计算和等待操作,而且一个服务通常不仅执行单一任务。

2.《Java并发编程实战》的推荐设置:

  • Ncpu表示CPU的数量。
  • Ucpu表示期望的CPU的使用率。
  • W/C表示等待时间与计算时间的比例。

比如说我们通过监控判断接口CPU计算时间是20ms,等待时间是80ms,期望CPU使用率是80%,那么根据公式得出:

线程数=CPU个数8*CPU使用率0.8*(1+(等待时间80ms/计算时间20ms))=32

在实际应用中,由于业务场景的复杂性,一个服务可能涉及多种操作,包括内存读写、计算、I/O等。因此,仅仅通过公式计算线程数可能过于理想化。当我们这样回答时,面试官显然是不会满意的。

业务程序中如何量化线程数?

此时项目中需要一个业务场景的多线程(或者线程池)来异步/并行执行业务流程。

以一个常规的接口处理为例,可能涉及以下流程:

sequenceDiagram participant Client participant Server participant Cache participant RPC participant DB Client->>+Server: 发起请求 Server->>+Server: 1、参数解析、参数校验 Server->>+Cache: 2、缓存查询数据 Cache-->-Server: return alt 缓存命中 Server-->>-Client: 返回结果 else 缓存未命中 Server->>+DB: 3、调用数据库查询数据 DB -->-Server: return Server->>+RPC: 4、调用RPC接口查询数据 RPC -->-Server: return Server->>+Server: 5、业务逻辑本地计算处理 Server->>+Cache: 6、更新缓存 Cache-->-Server: return Server->>+Server: 7、参数组装 Server-->>-Client: 返回结果 end

该接口涉及以下步骤:

  1. 参数解析、参数校验
  2. 缓存查询数据,如果查询到直接返回了
  3. 如果缓存没查到数据,调用数据库查询数据
  4. 调用RPC接口查询数据
  5. 业务逻辑本地计算处理
  6. 将计算后的数据更新到缓存
  7. 最后进行参数组装并返回

这个接口中,步骤2、3、4、6都涉及IO等待,其余步骤会涉及CPU计算。需要注意的是步骤2查询到缓存后直接返回了,不会执行后面的流程。

线程数计算误区

如果我们按照上面的公式来规划线程数的话,误差一定会很大。

做业务开发时,我们通常选择SpringBoot作为基础框架,使用Tomcat容器、druid连接池、并采用G1垃圾回收器。

在设置线程数时,我们常常受到误导。例如,一个主机上可能不仅部署了一个进程,一个进程中还有许多运行中的线程,同时druidJVMG1也都有各自的线程池和后台线程。这些线程都在当前进程、当前主机上运行,也占用CPU资源。

此外,CPU执行时会涉及CPU时间片轮转和线程切换,而高峰期数据库和RPC接口的响应时间也会有所不同。

如何设置线程数?

那么到底如何设置线程数呢?这个没有标准答案,我们一定要结合场景,跟面试官讲清楚。最好通过公式初步设置一个大概值,然后通过测试去找到一个最合适的线程数。同时,线程池最好支持动态调整,这样即时有问题,我们也能灵活的进行调整。

这样的解释能够更好地向面试官传达我们对于线程数设置的理解和灵活应对业务复杂性的能力。

相关推荐
Grey Zeng3 小时前
Java SE 25新增特性
java·jdk·jdk新特性·jdk25
追逐时光者4 小时前
精选 4 款基于 .NET 开源、功能强大的 Windows 系统优化工具
后端·.net
雨白4 小时前
Java 线程通信基础:interrupt、wait 和 notifyAll 详解
android·java
TF男孩4 小时前
ARQ:一款低成本的消息队列,实现每秒万级吞吐
后端·python·消息队列
bobz9654 小时前
进程和线程结构体的统一和差异
面试
AAA修煤气灶刘哥5 小时前
别让Redis「歪脖子」!一次搞定数据倾斜与请求倾斜的捉妖记
redis·分布式·后端
AAA修煤气灶刘哥5 小时前
后端人速藏!数据库PD建模避坑指南
数据库·后端·mysql
你的人类朋友6 小时前
什么是API签名?
前端·后端·安全
昵称为空C8 小时前
SpringBoot3 http接口调用新方式RestClient + @HttpExchange像使用Feign一样调用
spring boot·后端
架构师沉默8 小时前
设计多租户 SaaS 系统,如何做到数据隔离 & 资源配额?
java·后端·架构