面试官:线程池大小 + 线程数量到底设置多少?
阅读本文大概需要 7 分钟。
CPU 密集型的程序 - 核心数 + 1 I/O 密集型的程序 - 核心数 * 2
线程数和CPU利用率的小测试
public class CPUUtilizationTest {
public static void main(String[] args) {
//死循环,什么都不做
while (true){
}
}
}
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();
}
}
}
public class CPUUtilizationTest { public static void main(String[] args) throws InterruptedException { for (int n = 0; n < 1; n++) { new Thread(new Runnable() { 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(); } }}
线程数和CPU利用率的小总结
一个极端的线程(不停执行“计算”型操作时),就可以把单个核心的利用率跑满,多核心CPU最多只能同时执行等于核心数的“极端”线程数 如果每个线程都这么“极端”,且同时执行的线程数超过核心数,会导致不必要的切换,造成负载过高,只会让执行更慢 I/O 等暂停类操作时,CPU处于空闲状态,操作系统调度CPU执行其他线程,可以提高CPU利用率,同时执行更多的线程 I/O 事件的频率频率越高,或者等待/暂停时间越长,CPU的空闲时间也就更长,利用率越低,操作系统可以调度CPU执行更多的线程
线程数规划的公式
真实程序中的线程数
分析当前主机上,有没有其他进程干扰
分析当前JVM进程上,有没有其他运行中或可能运行的线程
设定目标
目标CPU利用率 - 我最高能容忍我的CPU飙到多少?
目标GC频率/暂停时间 - 多线程执行后,GC频率会增高,最大能容忍到什么频率,每次暂停时间多少?
执行效率 - 比如批处理时,我单位时间内要开多少线程才能及时处理完毕
……
梳理链路关键点,是否有卡脖子的点,因为如果线程数过多,链路上某些节点资源有限可能会导致大量的线程在等待资源(比如三方接口限流,连接池数量有限,中间件压力过大无法支撑等)
不断的增加/减少线程数来测试,按最高的要求去测试,最终获得一个“满足要求”的线程数**
Tomcat中的maxThreads,在Blocking I/O和No-Blocking I/O下就不一样 Dubbo 默认还是单连接呢,也有I/O线程(池)和业务线程(池)的区分,I/O线程一般不是瓶颈,所以不必太多,但业务线程很容易称为瓶颈 Redis 6.0以后也是多线程了,不过它只是I/O 多线程,“业务”处理还是单线程
附录
Java 获取CPU核心数
Runtime.getRuntime().availableProcessors()//获取逻辑核心数,如6核心12线程,那么返回的是12
Linux 获取CPU核心数
# 总核数 = 物理CPU个数 X 每颗物理CPU的核数
# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数
# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq
# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l
推荐阅读:
微信扫描二维码,关注我的公众号
朕已阅