线程池的实现原理
类图
"ThreadPoolExecutor
: mainLock
是独占锁,用来控制新增Worker
线程操作的原子性。termination
是该锁对应的条件队列。
Worker
继承AQS
并实现了Runnable接口,是具体承载任务的而对象。Worker
继承了AQS
,自己实现了简单不可重入独占锁,其中state=0
表示锁未被获取,state=1
表示锁已经被获取,state=-1
是常见Worker的默认状态,是为了避免该线程在运行runWorker
方法前被中断。
状态
"ThreadPoolExecutor中的ctl
是一个原子变量,用来记录线程池状态和线程池中的线程个数,类似于ReentrantReadWriteLock中使用一个变量来保存两种信息。
以下为与ctl
相关的变量与函数:
1 | private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); |
线程池的状态含义如下:
- RUNNING:接受新任务并处理阻塞队列里的任务。
- SHUTDOWN:拒绝新任务但是处理阻塞队列里面的任务。
- STOP:拒绝新任务并且抛弃阻塞队列里的任务,同时会中断正在处理的任务。
- TIDYING:所有任务都执行完后当前线程池活动线程数为0,将要调用terminated方法(相当于一个过渡状态)。
- TERMINATED: 终止状态,terminated方法调用完成后的状态。
源码分析
线程池执行任务 - execute
ThreadPoolExecutor的实现实际是一个生产-消费模型,当用户添加任务到线程池时相当于生产者生产元素,workers中的线程直接执行任务或者从任务队列里面获取任务(当没有空闲的Worker时,任务会被暂存于任务队列中)时相当于消费者消费元素。
1 | // 执行任务 |
核心线程执行逻辑 - Worker
任务提交到线程池后由Worker来执行。
1 | Worker(Runnable firstTask) { |
- 在构造函数中设置Worker的状态为
-1
是为了避免当前Worker在调用runWorker方法前被中断(当其他线程调用了shutdownNow方法,如果Worker状态>=0则会中断该线程)。 - runWorker中调用unlock方法时将state置为0,使Worker线程可被中断。
Worker
线程state
的状态机
"
processWorkerExit方法如下:
1 | private void processWorkerExit(Worker w, boolean completedAbruptly) { |
优雅型退出 - shutdown
调用shutdown后,线程池将不再接受新任务,但任务队列中的任务还是要执行的。
1 | public void shutdown() { |
强制退出 - shutdownNow
调用shutdownNow后,线程池将不会再接受新任务,并且会丢弃任务队列里面的任务且中断正在执行的任务,然后立刻返回任务队列里面的任务列表。
1 | public List<Runnable> shutdownNow() { |
等待线程池结束-awaitTermination
当线程调用awaitTermination后,当前线程会被阻塞,直到线程池状态变成TERMINATIED或等待超时才返回。
1 | public boolean awaitTermination(long timeout, TimeUnit unit) |