ThreadPoolExecutor源码解析
简介
线程池作用就是限制系统中执行线程的数量。
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;如果线程少了会浪费系统资源,多了又会造成系统拥挤效率不高。用线程池控制线程数量,使得其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有任务等待进程,则线程池中的线程处于等待。
主要属性
- RUNNING:线程池状态,运行中。此时线程池可以接受新的任务和处理等待队列中的任务
- SHUTDOWN:线程池状态,关闭。此时线程池不接受新的任务,但是会处理等待任务中的任务
- STOP:线程池状态,停止。此时,线程池不会接受新的任务也不会处理等待队列中的任务
- TIDYING:线程池状态。所有的任务都销毁。线程池状态转为此状态时,会调用terminated()方法
- TERMINATED:线程池状态,已终止。terminated方法执行完之后,线程池状态就变为这个。
- workQueue:任务队列。通常为ArrayBlockingQueue和LinkedBlockingQueue
- threadFactory:线程工厂。用于生成线程
- handler:线程池满了之后的拒绝策略
- keepAliveTime:空闲线程的保活时间。当线程总数超过了核心线程数之后,超过的那部分线程在空闲了指定的时间之后,就会被关闭。
- corePoolSize:核心线程数。如果没有设置**allowCoreThreadTimeOut(true)**,核心线程超过keepAliveTime也不会被回收
- maximumPoolSize:线程池的最大线程数
- defaultHandler:默认的拒绝策略。AbortPolicy
线程池的状态转换
线程池可以有以下状态的转换:
- RUNNING->SHUTDOWN:当调用了shutdown方法后
- RUNNING->STOP:当调用了shutDownNow方法后
- SHUTDOWN->STOP:当调用了shutDownNow方法后
- SHUTDOWN->TIDYING:当任务队列和线程池都清空后
- STOP->TIDYING:当任务队列清空后
- TIDYING->TERMINATED:当调用了terminated方法后
主要函数
构造方法
1 | public ThreadPoolExecutor(int corePoolSize, |
初始化各个参数
execute
1 | public void execute(Runnable command) { |
- 如果Command为null,返回空指针异常
- 如果当前执行的Worker数目小于corePoolSize。直接创建一个新的线程执行任务,返回
- 如果当前执行的worker数目大于等于corePoolSize,并且任务队列没有满的话,将任务放到队列中。否则执行第6步。
- 任务当如队列中之后,还要做一次recheck,以防另外一个线程在此时关闭了线程池。如果这个时候线程池不是RUNNING状态,将任务从队列中移除,调用拒绝策略
- 否则,查看当前的worker数目,如果为0的话,启动一个线程,去任务队列获取任务执行
- 新启动一个线程去任务队列执行任务,这次的线程数目上界就以maximumPoolSize为准,如果addWorker失败,就拒绝任务
addWorker
接下来我们看下addWorker方法
1 | private boolean addWorker(Runnable firstTask, boolean core) { |
Work是封装的一个内部类,它继承了AQS类,实现了Runnable接口。
Worker
1 | private final class Worker |
runWorker
接下来看一下runWorker方法
1 | final void runWorker(Worker w) { |
getTask
接下来看下getTask方法,它的作用是从阻塞队列中获取一个任务来执行
1 | private Runnable getTask() { |
processWorkerExit
接着再看看processWorkerExit方法
1 | private void processWorkerExit(Worker w, boolean completedAbruptly) { |
tryTerminate
接着再看看tryTerminate方法
1 | final void tryTerminate() { |
以上的线程池执行过程,可以用下面这个图来概括:
shutdown
接着看下线程池是如何关闭的
shutdown方法将线程池状态改成SHUTDOWN,线程池还能继续处理阻塞队列里的任务,并且会回收一些闲置的Worker。
1 | public void shutdown() { |
空闲线程
worker运行的时候会去任务队列拿数据(getTask方法),如果没有设置超时时间,就会一直阻塞等待,此时的worker就被称为空闲worker。由于worker也是一个AQS,在runWorker方法里会有一对lock和unlock操作,这对lock操作是为了确保Worker不是一个空闲Worker。
所以Worker被设计成一个AQS是为了根据Worker的锁来判断是否是空闲线程,是否可以被强制中断。
checkShutdownAccess
如果有SecurityManager的话,校验下当前线程是否有关闭的权限
接着再校验每个worker是否允许被中断
1 | /** |
interruptIdleWorkers
调用了重载方法interruptIdleWorkers(boolean onlyOne)
1 | /** |
interruptIdleWorkers(boolean )
参数传入false表示中断所有的空闲线程
1 | private void interruptIdleWorkers(boolean onlyOne) { |
shutdownNow
shutdownNow把线程池状态改成STOP状态,这样不会处理阻塞队列里的任务,也不会处理新的任务:
1 | public List<Runnable> shutdownNow() { |
interruptWorkers
1 | private void interruptWorkers() { |
interruptIfStarted
只要当前线程没有中断,就中断当前线程
1 | void interruptIfStarted() { |
drainQueue
1 | private List<Runnable> drainQueue() { |