多线程 - 如何合理配置线程池
总结
根据“任务的性质”分析
CPU 密集型任务
- 和内存打交道,大量计算。例如大数的计算,正则匹配
- 如何配置:
- CPU 密集型任务应配置尽可能小的线程,如配置 Ncpu+1 个线程的线程池(Ncpu 是处理器的核的数目),这样留一个空出来,用来做切换。。
- 如果线程太多,会造成线程在CPU内部的上下文切换。。CPU的线程上下文切换比指令执行耗时的更多。
IO 密集型任务
- 解释:和磁盘,网络,文件,数据库交互很多的。
- 如何配置:由于 IO 密集型任务线程并不是一直在执行任务,在操作的时间,是不消耗CPU的。不会经常在CPU内切换线程上下文,则应配置尽可能多的线程,如 2*Ncpu。
-
对于 IO 型的任务的最佳线程数,有个公式可以计算 Nthreads = NCPU * UCPU * (1 + W/C)
❑NCPU 是处理器的核的数目❑UCPU 是期望的 CPU 利用率(该值应该介于 0 和 1 之间)
❑W/C 是等待时间与计算时间的比率。等待时间与计算时间我们在 Linux 下使用相关的 vmstat 命令或者 top 命令查看。
-
混合型任务
- 解释:前两者的混合
- 如何配置:如果可以拆分,将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务。
- 只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐 量将高于串行执行的吞吐量。
- 如果这两个任务执行时间相差太大(例如:一个是常量时间,一个是正无穷),则没必要进行分解。
- 可以通过 Runtime.getRuntime().availableProcessors()方法获得当前设备的 CPU 个数。
根据“任务的优先级”分析
优先级不同的任务可以使用优先级队列 PriorityBlockingQueue 来处理。它可 以让优先级高的任务先执行。
根据“任务的执行时间”分析
执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先 级队列,让执行时间短的任务先执行。
根据“任务的依赖性(依赖数据库连接)”分析
依赖数据库连接池的任务,因为线程