ThreadPoolExecutor的参数说明
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
corePoolSize
核心线程数,创建线程池之后,默认情况下线程池中并没有任何的线程,而是等待任务到来才创建线程去执行任务,当线程池中的线程数目达到 corePoolSize后,新来的任务将会被添加到缓存队列中(workQueue),除非调用 ThreadPoolExecutor.prestartAllCoreThreads() 或者 ThreadPoolExecutor . prestartCoreThread() 方法(从这两个方法的名字就可以看出是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或一个线程)。如果不太确定这个参数的数量,可以设置成Runtime.getRuntime().availableProcessors()
核心线程会一直存活,即使没有任务需要执行;
当前活跃线程数小于corePoolSize时,即使线程池中有空闲线程时,也会创建新的线程;
设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭;
maximumPoolSize
线程池中的最大线程数,表示线程池中最多可以创建多少个线程,当线程池中的线程数等于 corePoolSize 并且 workQueue 已满,这时就要看当前线程数是否大于 maximumPoolSize,如果小于maximumPoolSize 定义的值,则会继续创建线程去执行任务, 否则将会调用去相应的任务拒绝策略来拒绝这个任务,而不是当线程池中的任务数超过 corePoolSize 后,线程池会继续创建线程,直到线程池中的线程数等于maximumPoolSize。另外超过 corePoolSize的线程被称做"Idle Thread", 这部分线程会有一个最大空闲存活时间(keepAliveTime),如果超过这个空闲存活时间还没有任务被分配,则会将这部分线程进行回收。
maxPoolSize>当前活跃线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
当前活跃线程数=maxPoolSize,线往任务队列里压入线程任务,如果任务队列已满,线程池会拒绝处理任务而抛出异常
keepAliveTime
控制"idle Thread"的空闲存活时间,这个idle Thread就是上面提到的超过 corePoolSize 后新创建的那些线程,默认情况下,只有当线程池中的线程数大于corePoolSize,且这些"idle Thread"并没有被分配任务时,这个参数才会起作用。另外,如果调用了 ThreadPoolExecutor.allowCoreThreadTimeOut(boolean) 的方法,在线程池中的线程数不大于corePoolSize,且这些core Thread 也没有被分配任务时,keepAliveTime 参数也会起作用。
unit
参数keepAliveTime的时间单位,共7种取值,在TimeUtil中定义,与keepAliveTime参数共同工作:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue(queueCapacity)
阻塞队列(任务队列的容量),如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到该队列当中,注意只要超过了 corePoolSize 就会把任务添加到该缓存队列,添加可能成功也可能不成功,如果成功的话就会等待空闲线程去执行该任务,若添加失败(一般是队列已满),就会根据当前线程池的状态决定如何处理该任务(若线程数 < maximumPoolSize 则新建线程;若线程数 >= maximumPoolSize,则会根据拒绝策略做具体处理)。这里要特别注意如果是synchronousQueue的时候,如果线程数=maximumPoolSize 后,会根据拒绝策略直接处理,而不是进行队列化处理。
常用的阻塞队列有:
ArrayBlockingQueue //基于数组的先进先出队列,此队列创建时必须指定大小;
LinkedBlockingQueue //基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
synchronousQueue //这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
threadFactory
线程工厂,用来为线程池创建线程,当我们不指定线程工厂时,线程池内部会调用Executors.defaultThreadFactory()
创建默认的线程工厂,其后续创建的线程优先级都是Thread.NORM_PRIORITY
。如果我们指定线程工厂,我们可以对产生的线程进行一定的操作。
handler
拒绝执行策略,当线程池的缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
ThreadPoolExecutor.AbortPolicy: // 丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy: // 也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy: // 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy: // 由调用线程处理该任务