JDK1.5中引入了强大的concurrent包,其中最经常使用的莫过了线程池的实现ThreadPoolExecutor,它给咱们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅至关于或低于单线程的效率。线程
ThreadPoolExecutor类可设置的参数主要有:队列
核心线程数,核心线程会一直存活,即便没有任务须要处理。当线程数小于核心线程数时,即便现有的线程空闲,线程池也会优先建立新线程来处理任务,而不是直接交给现有的线程处理。ci
核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认状况下不会退出。it
当线程数大于或等于核心线程,且任务队列已满时,线程池会建立新的线程,直到线程数量达到maxPoolSize。若是线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。
当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。若是allowCoreThreadTimeout设置为true,则全部线程均会退出直到线程数量为0。效率
是否容许核心线程空闲退出,默认值为false。线程池
任务队列容量。从maxPoolSize的描述上能够看出,任务队列的容量会影响到线程的变化,所以任务队列的长度也须要恰当的设置。queue
线程池按如下行为执行任务im
系统负载异常
参数的设置跟系统的负载有直接的关系,下面为系统负载的相关参数:时间
参数设置
corePoolSize:
每一个任务须要tasktime秒处理,则每一个线程每钞可处理1/tasktime个任务。系统每秒有tasks个任务须要处理,则须要的线程数为:tasks/(1/tasktime),即tasks*tasktime个线程数。假设系统每秒任务数为100~1000,每一个任务耗时0.1秒,则须要100*0.1至1000*0.1,即10~100个线程。那么corePoolSize应该设置为大于10,具体数字最好根据8020原则,即80%状况下系统每秒任务数,若系统80%的状况下第秒任务数小于200,最多时为1000,则corePoolSize可设置为20。
queueCapacity:
任务队列的长度要根据核心线程数,以及系统对任务响应时间的要求有关。队列长度能够设置为(corePoolSize/tasktime)*responsetime: (20/0.1)*2=400,即队列长度可设置为400。
队列长度设置过大,会致使任务响应时间过长,切忌如下写法:
LinkedBlockingQueue queue = new LinkedBlockingQueue();
这其实是将队列长度设置为Integer.MAX_VALUE,将会致使线程数量永远为corePoolSize,不再会增长,当任务数量陡增时,任务响应时间也将随之陡增。
maxPoolSize:
当系统负载达到最大值时,核心线程数已没法按时处理完全部任务,这时就须要增长线程。每秒200个任务须要20个线程,那么当每秒达到1000个任务时,则须要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。
keepAliveTime:
线程数量只增长不减小也不行。当负载下降时,可减小线程数量,若是一个线程空闲时间达到keepAliveTiime,该线程就退出。默认状况下线程池最少会保持corePoolSize个线程。
allowCoreThreadTimeout:
默认状况下核心线程不会退出,可经过将该参数设置为true,让核心线程也退出。
以上关于线程数量的计算并无考虑CPU的状况。若结合CPU的状况,好比,当线程数量达到50时,CPU达到100%,则将maxPoolSize设置为60也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法下降每一个任务的处理时间(tasktime)。