线程池的状态只有了解线程池的几个状态,才能读懂它的核心源码。所以先说说这几个状态 running:为线程池初始化时的默认状态,此状态会接收任务进行处理 shutdown: 该状态下的线程池不接收任何任务,但会等待正在运行的任务执行完。通常调用shutdown() 方法完成设置 stop: 该状态的线程池不接收任何任务,同时java培训不会等待正在运行的任务执行完毕。通常调用shutdownNow() 方法完成设置 tidying:该状态下的线程池内,没有任何线程和任务 terminated:该状态为线程池的终态,通常调用tryTerminate()方法完成设置 大多数情况下线程池的一个生命周期流转大概是 running -> (shutdown,stop)-> tidying -> terminated 这几个状态在ThreadPoolExecutor源码中,通过一个ctl的整型原子变量标识,高3位标识线程状态,低29位标识线程数量。翻看源码就能看到 核心源码分析
为线程池的核心方法,调用该方法任务就会执行,直接看下面代码注释吧 ( ) { ( ) (); .(); (() ) { ((, )) ; .(); } (() .()) { .(); ( () ()) (); (() ) (, ); } ((, )) (); } 以上为核心源码的分析,无非就是根据线程池情况添加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方法大致的逻辑就完了。可以再看看时序图,理清下几个方法和类之间的调用。
中断线程池的线程,会等待正在执行的线程结束执行,来看看源码它是怎么实现的 () { .; .(); { (); (); (); (); } { .(); } (); } 该方法我们比较关注的点是 interruptIdleWorkers方法,是怎样中断空闲Worker,然后是如何保证Worker执行完毕的?看看代码就知道了 ( ) { .; .(); { ( : ) { .; (.() .()) { { .(); } ( ) { } { .(); } } () ; } } { .(); } } 到这里,核心逻辑就是通过w这个锁来完成的。
() { ; .; .(); { (); (); (); (); } { .(); } (); ; () { .; .(); { ( : ) .(); } { .(); } } } 源码和shutdown差不多,只不过将线程池状态设置为stop,然后调用interruptWorkers 方法,看看worker方法。 () { .; .(); { ( : ) .(); } { .(); } } 代码中并没有获取w锁的逻辑,所以这个方法会直接中断所有线程,并不会等待那些正在执行任务的worker把任务执行完。
调用awaitTermination方法会一直阻塞等待线程池状态变为 terminated 才返回 或者等待超时返回。来看看代码就明白了 ( , ) { .(); .; .(); { (;;) { ((.(), )) ; ( ) ; .(); } } { .(); } } (1)处的代码已经告诉了该方法什么时候返回,就是mainLock锁的termination条件变量被唤醒返回。在上面分析中termination条件变量被唤醒是在执行tryTerminate()时完成的,因为内部调用termination.signalAll()。而tryTerminate() 方法被shutDown() 和shutDownNow() 调用过,所以如果要让awaitTermination 返回,调用这2个方法就行。 |
|