一、重要的成员变量
corePoolSize:核心线程池大小
maximumPoolSize:线程池最大线程数
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止
workQueue:一个阻塞队列,用来存储等待执行的任务
runState:表示线程池的当前状态
继承关系
二、线程池状态
volatile int runState;
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
当创建线程池后,初始时,线程池处于RUNNING状态;
调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。
三、任务执行原理
在ThreadPoolExecutor类中,最核心的任务提交方法是execute()方法,(通过submit也可以提交任务,但是实际上submit方法里面最终调用的还是execute()方法)
execute()方法
excute()中主要有两个方法用来将任务加入线程池:
如果线程池中当前线程数小于核心池大小 addIfUnderCorePoolSize(command)
如果线程池中当前线程数达到了核心池大小并且往任务队列中添加任务失败 addIfUnderMaximumPoolSize(command)
addIfUnderCorePoolSize()方法
- addIfUnderCorePoolSize()方法中首先获取锁
- 然后判断线程池中的线程数目是否小于核心池大小
- 然后判断线程池的状态是否为RUNNING
- 然后通过addThread()方法传入任务返回线程,如果返回不为空,则启动这个线程。
addThread()方法:
- 首先用传入的任务创建了一个Worker对象
- 然后调用线程工厂threadFactory创建了一个新的线程t(用于运行Worker)
- 又把thread传给Worker(Worker里面也要拿到thread的引用)
poolSize++; - 返回t
Worker
- 实现了Runnable接口
- 在while循环中如果task不为空则执行任务,执行完不断通过getTask方法从任务缓存队列里面去取任务并执行。
getTask方法
- 先判断当前线程池状态,如果runState为STOP或者TERMINATED,则直接返回null;如果为SHUTDOWN或者RUNNING,则从任务缓存队列取任务。
- 如果当前线程池的线程数大于核心池大小corePoolSize或者允许为核心池中的线程设置空闲存活时间,则调用poll(time,timeUnit)来取任务,这个方法会等待一定的时间,如果取不到任务就返回null。
- 最后根据取到的任务是否为null以及workerCanExit()来判断Worker是否可以退出。
概括来说:
- 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;
- 如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;
- 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;
- 如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。