分享

java开发之ThreadPoolExecutor源码分析

 IT小白在线 2021-10-18

线程池的状态

只有了解线程池的几个状态,才能读懂它的核心源码。所以先说说这几个状态

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个方法就行。


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多