如何合理的配置线程池参数

合理配置线程池要结合任务类型(CPU密集还是IO密集)、业务特点(ToB还是ToC)、机器资源来综合考量。

评估是否需要上并行

  1. 任务的可分解性:任务是否能被拆分成多个可以独立执行的子单元?如果任务本身是严格串行的,并行化没有意义。

  2. 计算资源:是否有足够的CPU核心来支持并行执行?在单核CPU上多线程主要是为了并发(应对I/O等待)、而不是真正的并行计算。

  3. 任务类型:

    1. CPU密集型任务:这类任务几乎不涉及IO、计算耗时高、适合使用较小的线程池、线程数一般为 CPU核心数+1。此时每个线程都在占用CPU执行计算、多了反而增加上下文切换的成本、得不偿失。这类任务适合并行化以充分利用多核CPU

    2. IO密集型任务:此类任务会频繁进行网络、磁盘等IO操作、线程经常阻塞等待IO完成。这时可以适当将线程数设2N.这类任务通过并发可以提高系统吞吐量和响应性\因为线程可以在等待I/O时释放CPU给其他任务

然后如果是IO密集型

  • 虚拟线程与CPU密集型任务:(ForkJoin任务窃取底层解决虚拟线程IO阻塞时的切换)

  • 轻量级与高并发: 虚拟线程创建和切换的成本极低、可以轻松创建数百万个。这使得它们非常适合处理大量并发的、大部分时间在等待I/O(如网络请求、数据库查询、文件读写)的任务。

  • I/O阻塞处理: 当虚拟线程遇到I/O阻塞时、它会从其底层的平台载体线程上卸载。这个平台载体线程并不会被阻塞、而是可以立即去执行另一个准备就绪的虚拟线程。当I/O操作完成后、原来的虚拟线程会重新提交给调度器,等待被某个可用的载体线程挂载并继续执行

  • 高效的平台线程利用: 这种机制使得少量的平台载体线程(通常数量与CPU核心数相关)能够高效地管理和执行海量的并发I/O任务、避免了传统平台线程因I/O阻塞而大量闲置的问题、从而极大提高了系统吞吐量

ToB 与 ToC 业务对线程池参数的影响

  • ToC (面向消费者) 应用:

    • 特点: 通常要求快速响应、用户体验至上、并发用户量可能波动大。

    • 线程池配置倾向:

      • maximumPoolSize 可以设置得相对较大、以应对突发流量。

      • workQueue 的长度可能不宜过长(或者使用 SynchronousQueue)、避免请求积压过多导致用户感知到的延迟增加。如果队列太长、用户可能已经不耐烦了

      • 拒绝策略:倾向于快速失败(如 ThreadPoolExecutor.AbortPolicy,抛出异常)。这使得客户端或上游服务可以更快地得到反馈(例如,知道请求失败)、从而可以进行重试、降级处理或向用户展示错误提示、而不是让用户长时间无响应地等待。

    • 总的来说可以:阻塞队列长度可以少点、最大线程数多点->优先保证响应速度和应对流量弹性的

  • ToB (面向企业) 应用:

    • 特点: 可能有大量稳定的并发任务、对整体吞吐量和数据处理的可靠性和稳定性要求高。单个任务的处理时间可能较长。任务数量多、传送数据量大

  • 线程池配置倾向:

    • corePoolSize 和 maximumPoolSize 、两者可能设置得更接近、或者 maximumPoolSize 根据预估的持续平均并发任务数来设定、而不是为了应对极端短暂的峰值。目标是维持一个相对稳定的处理能力。

    • workQueue 可以设置得相对较长(例如使用 LinkedBlockingQueue,其默认容量接近无限、或者一个容量较大的 ArrayBlockingQueue)。这样可以缓冲大量任务、确保在系统处理能力暂时跟不上任务到达速度时、任务不会被直接拒绝而丢失。

    • 拒绝策略倾向于更保守、更能保证任务不丢失的策略。例如:

    • ThreadPoolExecutor.CallerRunsPolicy:让提交任务的线程自己来执行这个任务。这既能保证任务被执行、也能间接起到减缓任务提交速度的背压效果。

    • 自定义拒绝策略,将任务持久化到磁盘或其他地方,后续再进行处理。

总的来说可以阻塞队列长度可以多点、最大线程数:maximumPoolSize 的设置不追求像ToC那样为了应对极端峰值而设得特别大、而是更多地基于预期的持续并发处理需求和系统资源(如CPU、内存、下游依赖的处理能力)来设定一个合理且相对稳定的值。

结合实际资源来设定

  • 比如内存较小的机器不适合设置过多线程。

  • 对于业务流量不稳定的场景、可以考虑使用 动态线程池(如 ThreadPoolExecutor 中允许设置核心线程数和最大线程数、并结合拒绝策略、空闲线程存活时间等)、根据负载动态扩展线程数、提升资源利用率和系统弹性。

拓展题:

题目1.

首先问:如果又想要并行优化效率又不想多线程打垮对面的系统,该怎么设计一个方案,就是又要快又要成功发送。

回答:可以Kafka的消费者控制消费逻辑、让对方控制Offerset提交、这样子就不会打崩别人的系统了。

继续问:但是对方已经提供了接口,不太可能给我们单独做一个消费者去消费

回答:发送方用Kafka消息队列控制发送的量,利用Kafka的事务和自定义批量发送逻辑来提高效率

题目2:

线程的创建和销毁有开销、线程过多效率会很低、多线程的情况下容易发生OOM的问题

题目3:

如何排查OOM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值