我相信大家都用过线程池,但是线程池数量设置为多少比较合理呢?

线程数的设置的最主要的目的是为了充分并合理地使用 CPU 和内存等资源,从而最大限度地提高程序的性能,因此让我们一起去探索吧!

首先要考虑到 CPU 核心数,那么在 Java 中如何获取核心线程数?

可以使用 Runtime.getRuntime().availableProcessor() 方法来获取(可能不准确,作为参考)

在确认了核心数后,再去判断是 CPU 密集型任务还是 IO 密集型任务:

  • CPU 密集型任务:比如像加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务,大部分场景下都是纯 CPU 计算
  • IO 密集型任务:比如像 MySQL 数据库、文件的读写、网络通信等任务,这类任务不会特别消耗 CPU 资源,但是 IO 操作比较耗时,会占用比较多时间

在知道如何判断任务的类别后,让我们分两个场景进行讨论:

CPU 密集型任务

对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 8 核的 CPU,每个核一个线程,理论上创建 8 个线程就可以了。

如果设置过多的线程数,实际上并不会起到很好的效果。此时假设我们设置的线程数量是 CPU 核心数的 2 倍,因为计算任务非常重,会占用大量的 CPU 资源,所以这时 CPU 的每个核心工作基本都是满负荷的,而我们又设置了过多的线程,每个线程都想去利用 CPU 资源来执行自己的任务,这就会造成不必要的上下文切换,此时线程数的增多并没有让性能提升,反而由于线程数量过多会导致性能下降。

因此,对于 CPU 密集型的计算场景,理论上线程的数量 = CPU 核数就是最合适的,不过通常把线程的数量设置为CPU 核数 +1,会实现最优的利用率。即使当密集型的线程由于偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程也能确保 CPU 的时钟周期不会被浪费,从而保证 CPU 的利用率。

如下图就是在一个 8 核 CPU 的电脑上,通过修改线程数来测试对 CPU