前言
前面一篇文章讲述了线程池的处理任务的流程以及一些基本概念,接下来对线程池源码进行分析;
正文
execute方法:
1 |
|
拒绝策略
拒绝策略方法是reject方法:
1 |
|
该方法最终会调用handler的rejectedExecution方法;handler是创建线程池时传入的拒绝策略参数,该参数需要实现RejectedExecutionHandler接口,而在ThreadPoolExecutor类中分别定义了四种拒绝策略:CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy;而线程池默认情况下是使用的AbortPolicy来作为拒绝策略方法;而AbortPolicy实现的接口的代码如下:
1 |
|
其实就是抛出异常,所以说线程池的拒绝策略为默认抛出异常;
说明: execute 方法主要是判断进入的任务进入哪一个流程(核心线程,队列,拒绝策略)
addWorker 方法
1 |
|
该方法使用CAS的方式对工作线程数量(ctl)进行改变,也就是最上边的那段使用了CAS进行并发控制的代码段;
Work类
Work
类是ThreadPoolExecutor
的一个内部类;继承了AbstractQueuedSynchronizer;
Work构造方法
1 |
|
该构造方法传入一个Runnable
的执行任务,使用ThreadPoolExecutor
类的线程工厂来创建一个线程来执行任务;
Work的run方法
1 |
|
该Work的线程将会调用runWorker方法
runWorker方法
在addWorker方法中已经启动了worker中的线程,现在runWorker就是执行任务
1 |
|
该方法主要负责执行任务,并且在执行任务前后分别进行了处理,可以在此自定义一些处理,比如任务执行时间,任务执行情况,线程池状态等等; 还有一点就是会不断循环的去获取队列中的任务,直到获取不到任务为止,最后再对worker进行处理
completedAbruptly:这个属性初始值为true,在任务执行完成后会改变为false,除非任务非正常执行完成,跳过了改变为false的哪一步;
最后一个finally中的代码只有非核心线程(非核心worker)才会进入,核心的worker会在getTask中阻塞等待获取队列中的任务;
getTask方法
runWorker方法通过该方法从队列中获取任务,代码如下:
1 |
|
说明: 疑点1:
- 这段代码的主要的任务就是将ctl减一(相当于就是任务执行完成,而且队列也为空,),但是判断的条件就比较多了,而使用的是CAS,这里就对并发进行了控制,始终保证只有一个线程会执行ctl减1,也就是线程回收;
- 判断条件主要就是工作线程是否大于最大线程数,是否超时判断,队列是否为空,工作线程是否大于1
- 这个点我能想到的触发场景就是:第一次从队列获取数据,但是获取为空,然后循环,在进入第二次循环后,队列判断前有新任务进入了队列,这个点才会被触发
其它: 如果是核心线程进入该方法,会根据allowCoreThreadTimeOut属性来判断是使用超时策略(poll)还是阻塞式(take)获取任务, 在没有设置allowCoreThreadTimeOut的情况下,且队列中没有任务,那么核心线程就会一直阻塞在这个位置, 如果设置了,那么该线程就会和其它非核心线程执行流程一样;
非核心则采取超时策略;超时过后返回null;
创建线程池时设置的超时策略就在这个方法中的获取队列任务时体现;
结合runWorker,getTask,processWorkerExit,即便是设置了allowCoreThreadTimeOut,如果队列不为空,则会一直循环的创建, 线程池会一直存活也在这个地方体现;
processWorkerExit 方法
源码:
1 |
|
这里主要是对worker进行回收,也就是worker执行到这个方法就完成了; 但是有个注意点:如果设置了allowCoreThreadTimeOut属性,所有的线程都会等待超时,并被回收;但是这时有任务进入队列(队列不为空), 但是又没有工作线程,这里则会重启一个线程来处理队列中的任务;
tryTerminate方法
源码:
1 |
|
这个方法很是关键:shutdown,shutdownNow,processWorkerExit等等方法均调用了该方法; 这三个方法通过不同的线程池状态进入,最后处理的结果也不相同;
shutdown方法
停止接收新的任务,队列中的任务还是会被执行;
源码:
1 |
|
这这个方法主要还是修改线程池状态,然后调用tryTerminate方法;
shutdownNow方法
源码:
1 |
|
可以看出shutdownNow和shutdown的流程差不多,唯一不同的就是状态值和shutdownNow会返回队列中未执行的任务;
##interruptIdleWorkers方法
源码:
1 |
|
注意这是两个方法;
这两个方法的主要作用就是中断worker集合中每个worker的Thread任务; 需要注意的是使用了Thread的interrupt方法;如果Thread正在执行任务中,那么这个方法会执行完成会关闭; 如果这个Thread在队列的take阻塞中,也会被中断掉;