线程池源码解析3.execute()方法

1.execute()方法

1.1大致流程

这里只是总结了一遍大致的流程,一些细节问题见下面的流程图或者参考源码。

  • 当提交任务时,首先判断当前线程池内的线程数是否达到了核心线程,没有达到核心线程数就开线程去执行任务,如果达到了核心线程数,就尝试将任务加入阻塞队列中。
  • 如果说队列也满了,就尝试继续开线程执行任务,如果此时线程池中的存活线程已经等于了maximumPoolSize,那么直接走拒绝策略。没有到达最大线程,则开启线程执行任务。

1.2流程图

在这里插入图片描述

1.3源码解析

   /*
    *   command可以是普通的Runnable实现类,也可以是FutureTask(本质也是一个Runnable)
    */   
   public void execute(Runnable command) {
    
    
        //command不能为NULL。
        if (command == null)
            throw new NullPointerException();
       
       	/* 
       	 * 获取内部的ctl的值赋值给c
       	 * 高3位表示线程池状态,低29位表示当前线程池的线程数量
       	 */
        int c = ctl.get();
        
        
        /*
         * workerCountOf(c)就是获取ctl的低29位,即当前线程池中存活的线程数量。
         * 条件成立:表示当前线程数量小于核心线程数量,此次提交任务,直接创建一个新的			 
         * worker(线程),对应线程池中多了一个新的线程。
         */
        if (workerCountOf(c) < corePoolSize) {
    
    
            
            /*
             * addWorker(Runnable firstTask, boolean core) 为创建worker并执行任务			  
             * 的过程,会创建worker对象,并且将command作为firstTask.
             *  
             *  @param firstTask 表示当前的任务
             *  @param core 表示此次创建的线程是否算到核心线程数的头上。
             */
            if (addWorker(command, true))
                /*创建成功后,直接返回。addWorker方法内部会启动新创建的worker,执行					
                 * firstTask
                 */
                return;
            
            /*
             * 执行到这条语句,说明addWorker()一定失败了。。。
             *  有几种可能? 
             *  1.存在并发现象,execute方法是可能有多个线程同时调用的,当						 
             *  workerCountOf(c) < corePoolSize条件成立时,其他线程可能也成立了,如			  
             *  果此时线程池中的线程数已经到达了上限等,那么就会失败
             *  
             *  2.当前线程池状态发生了改变。
             *   2.1如果当前线程池状态是非RUNNING,addWorker(firstTask != null, true|false)一定会失败
             * 
             *   2.2SHUTDOWN状态下,也有可能创建成功,前提是firstTask == null 并且当前队列不为空(特殊情况)
             *   
             */ 
            //再次获取一下ctl的值。
            c = ctl.get();
        }
       
        /*
         * 执行到这里有几种情况?
         * 1.当前线程数量已经达到了corePoolSize。
         * 2.addWorker()失败。
         */
       
       	/*
       	 * 条件成立:表示当前线程池处于running状态,则尝试将任务放到阻塞队列中
       	 */
        if (isRunning(c) && workQueue.offer(command)) {
    
    
            //执行到这里,说明当前任务已经入队,再次获取一下ctl的值
            int recheck = ctl.get();
            //根据ctl的值 判断当前线程池处于非RUNNING状态,则尝试从队列中移除任务
            if (!isRunning(recheck) && remove(command))
                //任务移除成功,走拒绝策略。
                reject(command);
            
            /*
             * 这里是一个担保机制,担保线程池是running状态,但是如果线程池中存活的线程是0
             * 的话,就会很尴尬,这里就调用addWorker()开一个线程去执行任务。
             */
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
       
        /*
         * 执行到这里,有几种情况
         *  1.任务入队失败
         *  2.当前线程池是非running状态。
         * 
         *  1.如果说队列满了,这个时候如果当前线程数量没有达到maximumPoolSize,会创建新
         *  的worker直接执行任务。如果达到了最大线程数,addWorker()就会失败,走拒绝策略
         *  2.如果线程池处于非running状态,调用addWorker()一定会失败,走拒绝策略。 
         */ 
        else if (!addWorker(command, false))
            //走拒绝策略
            reject(command);
    }

2.addWorker()

2.1总体流程分析

先判断当前线程池状态是否允许继续添加任务,允许添加的话,CAS操作将ctl的值尝试+1,CAS成功然后传入任务通过new Worker()的方式构造一个Worker,然后加锁尝试将worker对象放入线程池,如果加入线程池成功,释放锁后就调用start()执行任务。如果任务最终没有被执行,就需要执行后续的清理逻辑。

   /*
    *  @param firstTask可以为NULL,表示启动worker之后,worker自动从队列中获取任务,如
    *  果不是NULL,worker优先执行firstTask(内部任务)
    *  @param core 采用的线程数限制,如果为true,采用核心线程数限制,false采用
    *  maximumPoolSize线程数限制 (传入的参数一般都是false)
    *
    *  @return boolean 表示任务是否已经启动
    *  返回值总结: true表示创建worker成功且线程启动成功
    *             false: ①线程池状态大于SHUTDOWN时,一定会失败。
    *                     ②当前状态 = SHUTDOWN 但是队列中已经没有任务了或者当前状态是
    * 					  SHUTDOWN且队列未空,但是firstTask不为NULL。
    *                     ③当前线程池已经达到了指定指标(core或max)
    *                     ④ThreadFactory创建的线程是NULL。
    */
   private boolean addWorker(Runnable firstTask, boolean core) {
    
    
       
        // 自旋。
        retry: for (;;) {
    
    
            
            //获取当前的ctl值保存到c中
            int c = ctl.get();
            
            //rs:当前线程池的运行状态
            int rs = runStateOf(c);
			
            /*
             *  这个判断主要是为了判断当前线程池是SHUTDOWN状态,但是队列里还有任务尚未处理完,这个时候是允许添加worker(线程)的,
             * 但是不允许再次提交task。
             */
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null  &&
                   ! workQueue.isEmpty()))
                return false;
			
            //上面的代码,就是判断当前线程池的状态是否允许继续添加线程
            
            //内部自旋
            for (;;) {
    
    
                //获取当前线程池中的线程数量,
                int wc = workerCountOf(c);
                
                /*
                 * 根据传来的core参数判断当前线程数是否大于等于核心线程数或者是最大线程数。大于等于的话直接return false。
                 */
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                
                /*
                 * 尝试使用CAS方式更新ctl,将线程数量+1
                 *  成功:说明更新成功,结束外层自旋。
                 *  失败:说明有竞争,其他线程已经修改了ctl的值。或者外部线程可能调用了
                 *  shutdown或者shutdownNow(),导致线程池状态发生变化,CAS也会失败
                 */ 
                if (compareAndIncrementWorkerC ount(c))
                    //走到这,一定是CAS成功。结束外层自旋,继续向下执行外部代码。
                    break retry;
             
                //CAS失败,获取最新的ctl值
                c = ctl.get();  
                //判断当前线程池是否发生过变化,如果变化了,继续自旋,
                if (runStateOf(c) != rs)
                    /*
                     * 状态发生变化后,直接返回到外层循环,外层循环负责判断当前线程池状态
                     * 和是否允许创建线程
                     */
                    continue retry;
            }
        }
		
        //表示创建的worker是否已经启动
        boolean workerStarted = false;
       
        //表示创建的worker是否添加到了workers(HashSet)中
        boolean workerAdded = false;
       
        //w表示后面创建worker的一个引用
        Worker w = null;
        try {
    
    
            
            //创建Worker,执行完后,线程 "应该" 已经准备好了。
            w = new Worker(firstTask);
            
            //将新创建的worker节点的线程 赋值给t
            final Thread t = w.thread;
            
            /*
             *  为什么要做 t != null这个判断
             *  为了防止ThreadFactory实现类有bug,因为ThreadFactory是一个接口。
             */
            if (t != null) {
    
    
                
                //将全局锁的引用保存到mainLock中
                final ReentrantLock mainLock = this.mainLock;
                
                /*
                 * 尝试加锁,可能会阻塞,知道获取成功为止,同一时刻操纵线程池内部的相关操作,都必须持锁。
                 */
                mainLock.lock();
                
         //只要走到了这里,说明当前线程已经加锁成功,其他线程是无法修改当前线程池状态的
                try {
    
    
                    //获取线程池运行状态保存到rs中
                    int rs = runStateOf(ctl.get());
					
                    /*
                     * 条件一:判断当前线程池的状态是否正常
                     * 条件二: 判断当前线程池为SHUTDOWN状态并且firstTask为NULL,
                     *         其实就是判断是否是SHUTDOWN下的特殊状态(队列里还有任务)
                     */
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
    
    
                        
                        //这里防止程序员自定义ThreadFactory实现类时在内部就start了。
                        if (t.isAlive()) 
                            //抛出异常
                            throw new IllegalThreadStateException();
                        
                        //将创建的worker添加到线程集合(就是线程池)中。
                        workers.add(w);
                        
                        //获取最新线程池线程的数量
                        int s = workers.size();
                        
                        //条件成立,更新largestPoolSize 
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        
                        //更新标志位,表示线程已经追加到线程池中了。
                        workerAdded = true;
                    }
                } finally {
    
    
                    //释放全局锁
                    mainLock.unlock();
                }
                /*
                 *  条件成立:workerAdded为true,表示添加worker成功。
                 *  失败:表示线程池在lock之前,状态发生了变化,导致添加线程失败。
                 */
                if (workerAdded) {
    
    
                    //成功后,将线程启动。
                    t.start();
                    //启动标记设置为true。
                    workerStarted = true;
                }
            }
        } finally {
    
    
            //判断启动标记,
            if (!workerStarted)
  				/* 
  				 * 添加失败,需要做清理工作.
  				 */
                addWorkerFailed(w);
        }
        //返回任务是够已经启动。
        return workerStarted;
    }

3.addWorkerFaild

    private void addWorkerFailed(Worker w) {
    
    
        final ReentrantLock mainLock = this.mainLock;
        //加锁
        mainLock.lock();
        try {
    
    
            if (w != null)
                //从workers中移除失败的worker。
                workers.remove(w);
            //将ctl的值-1,
            decrementWorkerCount();
            //见后续SHUTDOWN()
            tryTerminate();
        } finally {
    
    
            //释放锁
            mainLock.unlock();
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_46312987/article/details/121598280