java开发之ThreadPoolExecutor源码分析
线程池的状态
只有了解线程池的几个状态,才能读懂它的核心源码。所以先说说这几个状态
running:为线程池初始化时的默认状态,此状态会接收任务进行处理
shutdown: 该状态下的线程池不接收任何任务,但会等待正在运行的任务执行完。通常调用shutdown() 方法完成设置
stop: 该状态的线程池不接收任何任务,同时java培训不会等待正在运行的任务执行完毕。通常调用shutdownNow() 方法完成设置
tidying:该状态下的线程池内,没有任何线程和任务
terminated:该状态为线程池的终态,通常调用tryTerminate()方法完成设置
大多数情况下线程池的一个生命周期流转大概是 running -> (shutdown,stop)-> tidying -> terminated
这几个状态在ThreadPoolExecutor源码中,通过一个ctl的整型原子变量标识,高3位标识线程状态,低29位标识线程数量。翻看源码就能看到

核心源码分析
execute(Runnable command)
为线程池的核心方法,调用该方法任务就会执行,直接看下面代码注释吧
( ) {
( ) ();
.();
(() ) {
((, ))
;
.();
}
(() .()) {
.();
( () ())
();
(() )
(, );
}
((, ))
();
}
以上为核心源码的分析,无非就是根据线程池情况添加Worker、任务入队、执行拒绝策略。可以看看下面这个流程图,可能会更清晰

到这里,我们可以来讲讲addWorker 了。这个方法会封装成一个Worker对象,然后运行任务。看看Worker对象的类图:

Worker实现Runnable接口、继承AbstractQueuedSynchronizer,持有一个Thread的成员变量。所以可以把Worker对象看成一个线程,同时拥有AbstractQueuedSynchronizer的属性和方法,因此它能够进行加锁和释放锁的操作。
ok,逐步跟进来看看addWorker方法里面的逻辑。
( , ) {
:
(;;) {
.();
();
(
(
.()))
;
(;;) {
();
(
( : ))
;
(())
;
.();
(() )
;
}
}
;
;
;
{
();
.;
( ) {
.;
.();
{
(.());
(
( )) {
(.())
();
.();
.();
( )
;
;
}
} {
.();
}
() {
.();
;
}
}
} {
( )
();
}
;
}
整体还不算复杂,核心就是根据传入的任务创建一个Worker对象,然后启动Worker。
下面来看看Worker启动的逻辑,前面说过了Worker实现Runnable接口,所以启动将会触发执行run方法,而run方法最终调的是runWorker()方法。
( ) {
.();
.;
. ;
.();
;
{
( ( ()) ) {
.();
(((.(), )
(.()
(.(), )))
.())
.();
{
(, );
;
{
.();
} ( ) {
; ;
} ( ) {
; ;
} ( ) {
; ();
} {
(, );
}
} {
;
.;
.();
}
}
;
} {
(, );
}
}
整个方法的逻辑其实也不算复杂,就是当前Worker不断死循环获取队列里面是否有任务。有,就加锁然后执行任务。无,就阻塞等待获取任务。那什么情况下才会跳出整个死循环,执行processWorkerExit呢?这里就需要看下getTask() 方法逻辑了。
() {
;
(;;) {
.();
();
( ( .())) {
();
;
}
();
;
(( ( ))
( .())) {
(())
;
;
}
{
.(, .) :
.();
( )
;
;
} ( ) {
;
}
}
}
最后,来看下processWorkerExit() 方法处理了哪些逻辑
( , ) {
()
();
.;
.();
{
.;
.();
} {
.();
}
();
.();
((, )) {
() {
: ;
( .())
;
(() )
;
}
(, );
}
}
这个方法主要就是移除Worker对象,然后尝试将线程池的状态更改为terminate。这里需要讲一下tryTerminate方法逻辑,因为它和线程池awaitTermination()方法有一定的关联,来看看它的代码。
() {
(;;) {
.();
(()
(, )
(() .()))
;
(() ) {
();
;
}
.;
.();
{
(.(, (, ))) {
{
();
} {
.((, ));
.();
}
;
}
} {
.();
}
}
}
到这里,线程池execute方法大致的逻辑就完了。可以再看看时序图,理清下几个方法和类之间的调用。

shutdown()
中断线程池的线程,会等待正在执行的线程结束执行,来看看源码它是怎么实现的
() {
.;
.();
{
();
();
();
();
} {
.();
}
();
}
该方法我们比较关注的点是 interruptIdleWorkers方法,是怎样中断空闲Worker,然后是如何保证Worker执行完毕的?看看代码就知道了
( ) {
.;
.();
{
( : ) {
.;
(.() .()) {
{
.();
} ( ) {
} {
.();
}
}
()
;
}
} {
.();
}
}
到这里,核心逻辑就是通过w这个锁来完成的。
shutdownNow
() {
;
.;
.();
{
();
();
();
();
} {
.();
}
();
; () {
.;
.();
{
( : )
.();
} {
.();
}
}
}
源码和shutdown差不多,只不过将线程池状态设置为stop,然后调用interruptWorkers 方法,看看worker方法。
() {
.;
.();
{
( : )
.();
} {
.();
}
}
代码中并没有获取w锁的逻辑,所以这个方法会直接中断所有线程,并不会等待那些正在执行任务的worker把任务执行完。
awaitTermination
调用awaitTermination方法会一直阻塞等待线程池状态变为 terminated 才返回 或者等待超时返回。来看看代码就明白了
( , )
{
.();
.;
.();
{
(;;) {
((.(), ))
;
( )
;
.();
}
} {
.();
}
}
(1)处的代码已经告诉了该方法什么时候返回,就是mainLock锁的termination条件变量被唤醒返回。在上面分析中termination条件变量被唤醒是在执行tryTerminate()时完成的,因为内部调用termination.signalAll()。而tryTerminate() 方法被shutDown() 和shutDownNow() 调用过,所以如果要让awaitTermination 返回,调用这2个方法就行。
