Java线程池总结
Contents
1.工作流程
1.不会初始化corePoolSize个线程,有任务来了才创建工作线程;
2.当核心线程满了之后不会立即扩容线程池,而是把任务堆积到工作队列中;
3.当工作队列满了以后扩容线程池,一直到线程个数达到maximumPoolSize为止;
4.如果队列已满且达到了最大线程后还有任务进来,按照拒绝策略处理;
5.当线程数大于核心线程数时,线程等待keepAliveTime后还是没有任务需要处理时,收缩线程到核心线程数;
2.参数设置
tasks,程序每秒需要处理的最大任务数量(假设系统每秒任务数为100~1000)
tasktime,单线程处理一个任务所需要的时间(假设每个任务耗时0.1秒)
responsetime,系统允许任务最大的响应时间(假设每个任务的响应时间不得超过2秒)
1.corePoolSize
每个任务需要耗时 taskTime
单线程每秒可以处理的任务数 = 1 / taskTime
系统每秒的任务数为tasks,需要的线程数为 tasks/(1/taskTime) 即 tasks * taskTime
例子: 系统每秒任务数为100到1000之间,每个任务耗时0.1秒,则需要100x0.1至1000x0.1,即10到100个线程。那么corePoolSize应该设置为大于10。
具体数字需要参考系统平均QPS, 峰值QPS
最好根据8020原则,即80%情况下系统每秒任务数,若系统80%的情况下任务数小于200,最多时为1000,则corePoolSize可设置为20
2.QueueCapacity
队列长度 = (corePoolSize / tasktime ) * responseTime (核心线程数 / 单个任务耗时) * 单任务最大响应时间 = (核心线程每秒可以处理的任务数) * 单任务最大响应时间
例子: (20/0.1)*2=400,即队列长度可设置为400
如果队列长度过长,则任务响应时间过长
3.maxPoolSize
当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程。每秒200个任务需要20个线程,那么当每秒达到1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。
4.keepAliveTime
线程数量只增加不减少也不行。当负载降低时,可减少线程数量,如果一个线程空闲时间达到keepAliveTiime,该线程就退出。默认情况下线程池最少会保持corePoolSize个线程。keepAliveTiime设定值可根据任务峰值持续时间来设定。
以上关于线程数量的计算并没有考虑CPU的情况。若结合CPU的情况,比如,当线程数量达到50时,CPU达到100%,则将maxPoolSize设置为60也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法降低每个任务的处理时间(tasktime)。
参考
Author tmackan
LastMod 2021-02-28