线程运行规则
手动设置线程池,就要合理设置最大线程数和核心线程数,按照网上大多数的说法,都是跟服务器的CPU有关
- 先看下机器的CPU核数,然后在设定具体参数:
System.out.println(Runtime.getRuntime().availableProcessors());
即 CPU核数 = Runtime.getRuntime().availableProcessors()
- 分析下线程池处理的程序是CPU密集型,还是IO密集型
- IO密集型:大量网络,文件操作
- IO密集型:核心线程数 = CPU核数 * 2
- CPU 密集型:大量计算,cpu 占用越接近 100%, 耗费多个核或多台机器
- CPU密集型:核心线程数 = CPU核数 + 1
- 注:IO密集型(某大厂实践经验)
- 核心线程数 = CPU核数 / (1-阻塞系数) 例如阻塞系数 0.8,CPU核数为4,则核心线程数为20
maxPoolSize
当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程。每秒200个任务需要20个线程,那么当每秒达到1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。还有说法就是 cpuNUM*2 或者是cpuNUM*4
keepAliveTime
线程数量只增加不减少也不行。当负载降低时,可减少线程数量,如果一个线程空闲时间达到keepAliveTiime,该线程就退出。默认情况下线程池最少会保持corePoolSize个线程。
allowCoreThreadTimeout
默认情况下核心线程不会退出,可通过将该参数设置为true,让核心线程也退出。
queueCapacity
任务队列的长度要根据核心线程数,以及系统对任务响应时间的要求有关。队列长度可以设置为(corePoolSize/tasktime)*responsetime: (20/0.1)*2=400,即队列长度可设置为400。
队列长度设置过大,会导致任务响应时间过长,切忌以下写法:
LinkedBlockingQueue queue = new LinkedBlockingQueue();
这实际上是将队列长度设置为Integer.MAX_VALUE,将会导致线程数量永远为corePoolSize,再也不会增加,当任务数量陡增时,任务响应时间也将随之陡增。