
线程池状态
ThreadPoolExecutor 使用 int 的高 3 位来表示线程池的状态,低 29 为表示线程池数量。「之所以以一个 int 来记录两个信息,而不是用两个 int 记录,是因为,使用一个 int 可以用 cas 原子操作进行赋值」
| 状态名 | 高3位 | 接收新任务 | 处理阻塞队列任务 | 说明 |
|---|---|---|---|---|
| RUNNING | 111 | Y | Y | |
| SHUTDOWN | 000 | N | Y | 不会接收新任务,但会处理阻塞队列剩余任务 |
| STOP | 001 | N | N | 会终端正在执行的任务,并抛弃阻塞队列的任务 |
| TIDYING | 010 | - | - | 任务全部执行完毕,活动线程为 0 即将进入终结 |
| TERMINATED | 011 | - | - | 终结状态 |
构造方法
1 | public ThreadPoolExecutor(int corePoolSize, |
corePoolSize- 核心线程数目「最多保留的线程数」
maximumPoolSize- 最大线程数目
- 救急线程数等于 =
maximumPoolSize - corePoolSize - 救急线程可以执行突发任务,比如任务队列选择有界队列,任务的数量超过了队列大小,就会创建
maximumPoolSize - corePoolSize数目的救急线程来救急
- 救急线程数等于 =
- 最大线程数目
keepAliveTime- 生存时间 - 针对救急线程
unit- 时间单位 - 针对救急线程
workQueue- 阻塞队列
threadFactory- 线程工厂 - 可以为线程创建时起个好名字
handler- 拒绝策略
关于上述的用法可以参考 自定义阻塞队列
如果线程达到 maximumPoolSize 任有新任务,则会执行拒绝策略,拒绝策略由 JDK 提供了 4 种实现
AbortPolicy- 让调用者抛出
RejectedExecutionException异常,这是默认策略
- 让调用者抛出
CallerRunsPolicy- 让调用者运行任务
DiscardPolicy- 放弃本次任务
DiscardOldestPolicy- 放弃队列中最早的任务,本任务取而代之
除此之外,其他框架的实现如下
Dubbo- 在抛出
RejectedExecutionException异常前会记录日志,并dump线程栈信息,方便定位问题
- 在抛出
Netty- 创建一个新的线程执行任务
ActiveMQ- 带超时等待(60s)尝试放入队列
PinPoint- 使用了拒绝策略链,会逐一尝试策略链中每种拒绝策略
当高峰过去后,超过 corePoolSize 的救急线程,如果有一段时间没有任务做,需要结束节省资源,这个时间由 keepAliveTime 和 unit 控制。
根据这个构造方法,JDK Executors 类中提供了众多工厂方法来创建各种用途的线程池。