菜鸟笔记
提升您的技术认知

JAVA应用中线程池设置多少合适?

1、机器配置:

        4核8g内存

2、核心线程

        就是cpu核数就行

3、最大线程数多少合适?

    线程池设置多大,并没有固定答案, 需要结合实际情况不断的测试才能得出最准确的数据.

4、理论基础

  • 一个 CPU 核心,某一时刻只能执行一个线程的指令
  • 一个极端的线程,就可以把单个核心的利用率跑满,多核心 CPU 最多同时执行等于核心数的 “极端” 线程数
  • 如果每个线程都这么 “极端”,且同时执行的线程数超过核心数,会导致不必要的切换,造成负载过高,只会让执行更慢
  • I/O 等暂停类操作时,CPU 处于空闲状态,操作系统调度 CPU 执行其他线程,可以提高 CPU 利用率,同时执行更多的线程
  • I/O 事件的频率频率越高,或者等待 / 暂停时间越长,CPU 的空闲时间也就更长,利用率越低,操作系统可以调度 CPU 执行更多的线程

5、测试验证(测试机器12cpu)

一个线程跑满一个核心的利用率

public class CPUUtilizationTest {
	public static void main(String[] args) {
		//死循环,什么都不做
		while (true){
		}
	}
}

从图上可以看到,我的 3 号核心利用率已经被跑满了

6个线程

public class CPUUtilizationTest {
	public static void main(String[] args) {

		for (int j = 0; j < 6; j++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					while (true){
					}
				}
			}).start();
		}
	}
}

此时再看 CPU 利用率,1/2/5/7/9/11 几个核心的利用率已经被跑满

12 个线程:所有核的cpu利用率都跑满

有io操作

上面的例子中,程序不停的循环什么都不做,CPU 要不停的执行指令,几乎没有啥空闲的时间。如果插入一段 I/O 操作呢,I/O 操作期间 CPU 是空闲状态,CPU 的利用率会怎么样呢?先看看单线程下的结果:

public class CPUUtilizationTest {
	public static void main(String[] args) throws InterruptedException {

		for (int n = 0; n < 1; n++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					while (true){
                        //每次空循环 1亿 次后,sleep 50ms,模拟 I/O等待、切换
						for (int i = 0; i < 100_000_000l; i++) { 
						}
						try {
							Thread.sleep(50);
						}
						catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		}
	}
}

只有9 号核心的利用率较高,大但也才 50%,和前面没有 sleep 的 100% 相比,已经低了一半了。现在把线程数调整到 12 个看看:

单个核心的利用率 60 左右

6、计算公式

7、决定最大线程数的流程:

  1. 分析当前主机上,有没有其他进程干扰
  2. 分析当前 jvm 进程上,有没有其他运行中或可能运行的线程
  3. 设定目标
    • 目标 CPU 利用率 - 我最高能容忍我的 CPU 飙到多少?
    • 目标 GC 频率 / 暂停时间 - 多线程执行后,GC 频率会增高,最大能容忍到什么频率,每次暂停时间多少
  4. 不断的增加 / 减少线程数来测试,按最高的要求去测试,最终获得一个 “满足要求” 的线程数