Java并发编程-如何设置线程池大小?

551 阅读4分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

前言

如何设置线程池大小? 其实没有一个明确的答案, 可能我们随便设置的线程池大小在线上运行也没有出现问题, 减少线程切换, 提高系统利用率,可能最优的配置需要配合压测之后才能得出.

所以本篇文章也没有给出一个确切的答案, 结合自己的工作经验和一些他人的经验, 总结一些如何配置线程池的一些思路.

线程池系列

Java并发编程-线程池(一)
Java并发编程-线程池源码分析(二)
Java并发编程-JDK线程池和Spring线程池(三)
Java并发编程-线程池优雅关闭(四)
Java并发编程-阻塞队列BlockingQueue

1. 合理配置线程池

要想合理地配置线程池,就必须首先分析任务特性,可以从以下几个角度来分析。

  1. 任务的性质, CPU密集型任务、IO密集型任务和混合型任务。
  2. 任务的优先级:高、中和低。
  3. 任务的执行时间:长、中和短。
  4. 任务的依赖性:是否依赖其他系统资源,如数据库连接。

线程池参数.png

2. 动态化线程池

线程池的配置几个参数核心线程数大小,阻塞队列大小,最大线程数大小和空闲线程回收的时间等.

美团技术团队其实提供了一个很好的解决方案, 文章详情参考:Java线程池实现原理及其在美团业务中的实践

基本原理:

JDK原生线程池ThreadPoolExecutor提供了如下几个public的setter方法,如下图所示:

image.png

通过业务系统队列等待任务告警阈值、活跃度告警等等。去动态调整线程池的参数. 这个其实给我们打开了一个思路, 对于业界没有一个统一标准的事情, 这个其实也是一个比较好的解决方案, 实现的成本也不高.

3. 线程池监控

如果在系统中大量使用线程池,则有必要对线程池进行监控,方便在出现问题时,可以根 据线程池的使用状况快速定位问题。

  • taskCount:线程池需要执行的任务数量。
  • completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount。
  • largestPoolSize:线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过.
  • getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减。
  • getActiveCount:获取活动的线程数。

当然也可以通过继承线程池来自定义线程池,重写线程池的beforeExecute、afterExecute和terminated方法,也可以在任务执行前、执行后和线程池关闭前执行一些代码来进行监控。例如,监控任务的平均执行时间、最大执行时间和最小执行时间等。这几个方法在线程池里是空方法。

image.png

最后

上面这些可以作为我们日常设置线程大小作为一个参考, 真正实际项目中可能没有这么复杂, 人力成本监控成本都需要综合去做权衡, 可能作业务系统面对这种流量激增或者并发量超大, 可以在业务流程上去做一些优化, 比如用队列, 比如说扩容. 但是如果你是作为一个中间件, 提供高并发的一个工具, 线程池的监控就非常有必要了, 因为一个小的提升带来整个的效率的提升是非常可观的.

参考

深入理解Java线程池:ThreadPoolExecutor
Java线程池实现原理及其在美团业务中的实践