获取CPU核数,然后在设定具体参数
System.out.println(Runtime.getRuntime().availableProcessors());
即CPU核数 = Runtime.getRuntime().availableProcessors()
分析下线程池处理的程序是CPU密集型,还是IO密集型
粗粒度设置
CPU密集型:
核心线程数 = CPU核数 + 1
IO密集型:
核心线程数 = CPU核数 * 2
核心线程数 = CPU核数 / (1-阻塞系数)
利特尔法则设置
定义:一个系统请求数等于请求的到达率与平均每个单独请求花费的时间之乘积
举例:假设服务器单核的,对应业务需要保证请求量(QPS):10 ,真正处理一个请求需要 1 秒,那么服务器每个时刻都有 10 个请求在处理,即需要 10 个线程
公式:
线程池大小 = ((线程 IO time + 线程 CPU time )/ 线程 CPU time )* CPU数目
举例:假设服务器4核,平均IO时间为400ms,cpu处理时间为100ms, 线程应设置为20
基于压测的方式和期望CPU利用率
《Java并发编程实战》一书中,Brian Goetz和合著者们为线程池大小的优化提供了不少中肯的建议。这非常重要,如果线程池中线程的数量过多,最终它们会竞争稀缺的处理器和内存资源,浪费大量的时间在上下文切换上。反之,如果线程的数目过少,正如你的应用所面临的情况,处理器的一些核可能就无法充分利用。Brian Goetz建议,线程池大小与处理器的利用率之比可以使用下面的公式进行估算:
N-threads = N-CPU * U-CPU * (1 + W/C)
其中:
N-CPU是处理器的核的数目
U-CPU是期望的CPU利用率(该值应该介于0和1之间)
W/C是等待时间与计算时间的比率
最后根据压力测试进行微调
最大线程数
原则上就是性能最高线程数,因为此时性能已经是最高,再设置比他大的线程数反而性能变低。极端情况下才会使用到最大线程数,正常情况下不应频繁出现超过核心线程数的创建。