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、决定最大线程数的流程:
- 分析当前主机上,有没有其他进程干扰
- 分析当前 jvm 进程上,有没有其他运行中或可能运行的线程
- 设定目标
- 目标 cpu 利用率 - 我最高能容忍我的 cpu 飙到多少?
- 目标 gc 频率 / 暂停时间 - 多线程执行后,gc 频率会增高,最大能容忍到什么频率,每次暂停时间多少
- 不断的增加 / 减少线程数来测试,按最高的要求去测试,最终获得一个 “满足要求” 的线程数