创建线程池是需要指定如下几个参数,如:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

1、每个参数的含义及要点:

参数名

含义

注意要点

corePoolSize

核心线程数,线程池中维护的最小线程数量(包含活跃和空闲的线程数量)

1、线程池创建后,不是默认就会创建corePoolSize大小的线程数,而是有任务提交了才会开始创建线程

2、线程池中维持着corePoolSize大小的线程数,包含活跃和空闲线程

3、默认情况核心线程数即使为空闲的状态,keepAliveTime也不会生效,线程池中始终有corePoolSize大小数量的线程数

4、如果设置了allowCoreThreadTimeOut = true,那么核心线程也会在keepAliveTime时间到达后销毁,线程池中维护的线程数可能为0

maximumPoolSize

最大线程数,线程池允许创建的最大线程数量

1、maximumPoolSize 一般大于corePoolSize的值

2、如果maximumPoolSize = corePoolSize,那么该线程池是固定大小的线程池

keepAliveTime

线程池中空闲的线程保活时间

1、默认情况下(allowCoreThreadTimeOut = false),只有当线程池中的运行线程数量超过了corePoolSize时,keepAliveTime才会起作用,即keepAliveTime只对超出corePoolSize部分的线程起作用(举例说明:corePoolSize = 10,当前有15个线程在运行,此时运行线程超过了核心线程数,当线程执行完任务之后处于空闲时,当时间达到keepAliveTime的临界值后,有5个线程会被销毁,线程池中最后只会有10个可用的线程数)

2、如果线程池设置了allowCoreThreadTimeOut = true,那么keepAliveTime同样对核心线程启作用,即核心线程中线程空闲下来后,也会在时间达到keepAliveTime的临界值后销毁,线程池中的线程数可以为0

unit

保活时间单位(例如:秒,毫秒等)

TimeUnit.DAYS; // 天

TimeUnit.HOURS;// 小时

TimeUnit.MINUTES; // 分

TimeUnit.SECONDS;// 秒

TimeUnit.MILLISECONDS;// 毫秒

TimeUnit.MICROSECONDS;// 微秒

TimeUnit.NANOSECONDS;// 纳秒

workQueue

任务阻塞队列,当任务数超过当前线程池中的核心线程数量时,切队列未满,需要执行的任务会优先被放入到阻塞队列中进行等待

参考3

threadFactory

线程工厂对象,用来创建新的线程实例

可自定义

handler

拒绝执行处理策略

参考4

2、线程增长过程讲解:
corePoolSize、maximumPoolSize、workQueue:
ThreadPoolExecutor会根据这几个参数的边界内自动调整线程池中线程数量的大小,当执行execute(java.lang.Runnable)方法提交新任务时:

运行线程数(current) < corePoolSize 时

即使线程池中有空闲的线程,也会创建新的线程来执行新提交的任务
运行线程数(current) >= corePoolSize 时,此时说明核心线程数全部都处于繁忙状态中,新提交任务后,可能存在如下几种情况:
如果workQueue阻塞队列未满,则新的任务会被放入到队列中去等待空闲线程来进行执行,而不会创建新的线程
如果workQueue阻塞队列已满,且运行线程数 < maximumPoolSize 时,则会创建新的线程来执行新的任务
如果workQueue阻塞队列已满,且运行线程数 >= maximumPoolSize 时,则会通过handler策略来处理新的任务(handler策略方针后面会介绍)

任务处理的优先级(重复总结上面的规则,这个规则非常重要):

优先使用corePooSize范围内的线程
当核心线程都处于繁忙状态时,且阻塞队列未满,任务会被放入到阻塞队列中,而不是创建新线程来执行任务,等核心线程有空闲时,空线程会从阻塞队列中取出任务去执行
当阻塞队列已满,且当前运行线程数再运行的最大线程数范围内,则会创建新的线程来执行任务
当阻塞队列已满,且当前运行线程数达到线程池所运行的最大线程范围时,新的任务提交会被拒绝处理,拒绝处理的策略有多种方式,可以选择和自定义

3、使用的阻塞队列:

BlockingQueue 类型

特性及使用场景

ArrayBlockingQueue

有界队列,先进先出(FIFO)类型,需要指定队列大小,如果队列满了,会触发线程池的RejectedExecutionHandler拒绝处理策略

LinkedBlockingQueue

无界队列,FIFO类型,可以无限向队列中添加任务,直到内存溢出

SynchronousQueue

无界队列,一种特殊的阻塞队列,其中每个put操作(生产)必须等待一个take操作(消费),反之亦然。可以理解为没有容量的无界队列

PriorityBlockingQueue

优先级队列,线程池会优先选取优先级高的任务进行执行,队列中的任务必须实现Comparable接口(该队列使用极少)

4、拒绝处理策略方针:

拒绝处理策略通常是针对线程池中的有界队列而言的,无界对列,不存在队列已满的情况;当有界队列达到临界值后,新任务需要处理时会有问题,针对这种问题,线程池提供了以下几种处理策略:

RejectedExecutionHandler 类型

特性及效果

CallerRunsPolicy

如果任务添加失败,且线程池未关闭的情况下,那么调用线程(主线程)自己会调用执行器中的execute()方法来执行该任务

AbortPolicy

线程池默认的策略方针,如果有任务添加失败,则会丢弃掉该任务,并抛出RejectedExecutionException异常

DiscardPolicy

如果任务添加失败,则会丢弃掉该任务,且不抛出任何异常

DiscardOldestPolicy

如果任务添加失败,会将队列中最早入队的任务移除poll(),再尝试添加,如果还失败,则会按此策略不断的重试

自定义策略方针

如果以上的策略方针都不能满足要求,那么可以自定义符合场景的policy;实现RejectedExecutorHandler接口中的rejectedExecution()方法即可