前言
随着多核CPU的发展,多线程编程的应用越来越广泛,为了降低频繁创建线程,销毁线程所产生额外的资源开销,推出了线程池技术。使用线程池技术我们需要设置核心线程数与最大线程数,许多中间件也会将这两个参数交由我们自己设置,那么如何科学合理的去设置这两大参数呢?下面我们来一起研究一下。
方案
一般我们的程序都会分为以下几种类型,CPU密集型(计算密集型)、IO密集型、混合型,针每种类型的程序我们有不同的配置方案。
1 CPU密集型
CPU密集型也就是计算密集型,常常指算法复杂的程序,需要进行大量的逻辑处理与计算,CPU在此期间是一直在工作的。
在这种情况下CPU的利用率会非常高,我们的最大核心数设置为CPU的核心数即可。
这种情况下CPU几乎满负荷运行,我们配置的数字在大也没有效果,反而会增大额外的切换开销。
在《Java Concurrency in Practice》中,推荐将CPU密集型最大线程数设置为最大线程数 = CPU核心数 + 1,这样能发挥最高效率。
核心线程数一般会设置为 核心线程数 = 最大线程数 * 20%。
如下图所示,CPU密集型更多的是计算任务会持续占用CPU。
2 IO密集型
IO密集型是指我们程序更多的工作是在通过磁盘、内存或者是网络读取数据,在IO期间我们线程是阻塞的,这期间CPU其实也是空闲的,这样我们的操作系统就可以切换其他线程来使用CPU资源。
通常在进行接口远程调用,数据库数据获取,缓冲数据获取都属于IO操作。
这时我们线程数可以通过以下公式进行计算:最大线程数 = CPU核心数 / (1 – 阻塞占百分比)。
我们很好理解比如在某个请求中,请求时长为10秒,调用IO时间为8秒,这时我们阻塞占百分比就是80%,有效利用CPU占比就是20%,假设是八核CPU,我们线程数就是8 / (1 – 80%) = 8 / 0.2 = 40个。
也就是说 我们八核CPU在上述情况中,可满负荷运行40个线程。这时我们可将最大线程数调整为40,在系统进行IO操作时会去处理其他线程。
通常我们会设置为最大线程数 = CPU核心数 * 2。
核心线程数一般会设置为 核心线程数 = 最大线程数 * 20%。
如下图所示,IO密集型是同一个任务只有部分时间是在进行计算,很长时间都在进行IO阻塞。这样CPU同时刻就能处理更多的任务。
3 混合型
混合型程序,指既包含CPU密集型,又包含IO密集型。
对于此类程序,我们可以将任务划分成cpu密集型任务与IO密集型任务,分别针对这两种任务使用不同的线程池去处理。这样我们就可以针对这两种情况对线程池配置不同的参数。