线程池状态
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
类中提供了众多工厂方法来创建各种用途的线程池。