了解下JUC的线程池学习五(addWorker方法源码分析)

1.方法:boolean addWorker(Runnable firstTask, boolean core)

   方法的第一的参数可以用于直接传入任务实例,

   第二个参数用于标识将要创建的工作线程是否核心线程。

 

2.方法源码

    // 添加工作线程,如果返回false说明没有新创建工作线程,如果返回true说明创建和启动工作线程成功

   private boolean addWorker(Runnable firstTask, boolean core) {
       retry: 
         // 注意这是一个死循环 - 最外层循环
      for (int c = ctl.get();;) {
           // 这个是十分复杂的条件,这里先拆分多个与(&&)条件:
           // 1. 线程池状态至少为SHUTDOWN状态,也就是rs >= SHUTDOWN(0)
          //  2. 线程池状态至少为STOP状态,也就是rs >= STOP(1),或者传入的任务实例firstTask不为null,或者任务队列为空
          //  其实这个判断的边界是线程池状态为shutdown状态下,不会再接受新的任务,
          //  在此前提下如果状态已经到了STOP、或者传入任务不为空、或者任务队列为空(已经没有积压任务)都不需要添加新的线程
         if (runStateAtLeast(c, SHUTDOWN)
              && (runStateAtLeast(c, STOP)
                  || firstTask != null
                  || workQueue.isEmpty()))
                return false;
         // 注意这也是一个死循环 - 二层循环
         for (;;) {
             // 这里每一轮循环都会重新获取工作线程数wc
             // 1. 如果传入的core为true,表示将要创建核心线程,通过wc和corePoolSize判断,
             // 如果wc >= corePoolSize,则返回false表示创建核心线程失败
             // 1. 如果传入的core为false,表示将要创非建核心线程,通过wc和maximumPoolSize判断,
             // 如果wc >= maximumPoolSize,则返回false表示创建非核心线程失败
             if (workerCountOf(c)
                 >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                 return false;
             // 成功通过CAS更新工作线程数wc,则break到最外层的循环
             if (compareAndIncrementWorkerCount(c))
                 break retry;
             // 走到这里说明了通过CAS更新工作线程数wc失败,这个时候需要重新判断线程池的状态是否由RUNNING已经变为SHUTDOWN
             c = ctl.get();  // Re-read ctl
             // 如果线程池状态已经由RUNNING已经变为SHUTDOWN,则重新跳出到外层循环继续执行
             if (runStateAtLeast(c, SHUTDOWN))
                 continue retry;
                // 如果线程池状态依然是RUNNING,CAS更新工作线程数wc失败说明有可能是并发更新导致的失败,则在内层循环重试即可
                 // else CAS failed due to workerCount change; retry inner loop
               }
           }
            // 标记工作线程是否启动成功
            boolean workerStarted = false;
            // 标记工作线程是否创建成功
            boolean workerAdded = false;
            Worker w = null;
         try {
               // 传入任务实例firstTask创建Worker实例,Worker构造里面会通过线程工厂创建新的Thread对象,所以下面可以直接操作Thread t = w.thread
               // 这一步Worker实例已经创建,但是没有加入工作线程集合或者启动它持有的线程Thread实例
               w = new Worker(firstTask);
               final Thread t = w.thread;
               if (t != null) {
                    // 这里需要全局加锁,因为会改变一些指标值和非线程安全的集合
                   final ReentrantLock mainLock = this.mainLock;
                   mainLock.lock();
                try {
                     // Recheck while holding lock.
                     // Back out on ThreadFactory failure or if
                     // shut down before lock acquired.
                     int c = ctl.get();
                     // 这里主要在加锁的前提下判断ThreadFactory创建的线程是否存活或者判断获取锁成功之后线程池状态是否已经更变为SHUTDOWN
                     // 1. 如果线程池状态依然为RUNNING,则只需要判断线程实例是否存活,需要添加到工作线程集合和启动新的Worker
                     // 2. 如果线程池状态小于STOP,也就是RUNNING或者SHUTDOWN状态下,
                     // 同时传入的任务实例firstTask为null,则需要添加到工作线程集合和启动新的Worker
                     // 对于2,换言之,如果线程池处于SHUTDOWN状态下,同时传入的任务实例firstTask不为null,则不会添加到工作线程集合和启动新的Worker
                     // 这一步其实有可能创建了新的Worker实例但是并不启动(临时对象,没有任何强引用),这种Worker有可能成功下一轮GC被收集的垃圾对象
                     if (isRunning(c) ||
                         (runStateLessThan(c, STOP) && firstTask == null)) {
                           if (t.isAlive()) // precheck that t is startable
                                 throw new IllegalThreadStateException();
                            // 把创建的工作线程实例添加到工作线程集合
                            workers.add(w);
                            int s = workers.size();
                            // 尝试更新历史峰值工作线程数,也就是线程池峰值容量
                           if (s > largestPoolSize)
                                    largestPoolSize = s;
                                    // 这里更新工作线程是否启动成功标识为true,后面才会调用Thread#start()方法启动真实的线程实例
                                    workerAdded = true;
                            }
                      } finally {
                              mainLock.unlock();
                       }
                       // 如果成功添加工作线程,则调用Worker内部的线程实例t的Thread#start()方法启动真实的线程实例
                      if (workerAdded) {
                                t.start();
                               // 标记线程启动成功
                               workerStarted = true;
                       }
                  }
            } finally {
                    // 线程启动失败,需要从工作线程集合移除对应的Worker
                    if (! workerStarted)
                               addWorkerFailed(w);
            }
           return workerStarted;
        }
         // 添加Worker失败
         private void addWorkerFailed(Worker w) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                 try {
                     // 从工作线程集合移除之
                     if (w != null)
                          workers.remove(w);
                          // wc数量减1   
                          decrementWorkerCount();
                          // 基于状态判断尝试终结线程池
                          tryTerminate();
                     } finally {
                             mainLock.unlock();
                     }
            }
        注:Doug Lea大神十分喜欢复杂的条件判断,而且单行复杂判断不喜欢加花括号,像下面这种代码在他编写的很多类库中都比较常见:
        if (runStateAtLeast(c, SHUTDOWN)
                 && (runStateAtLeast(c, STOP)
                  || firstTask != null
                  || workQueue.isEmpty()))
                   return false;
          // ....
          //  代码拆分一下如下
          boolean atLeastShutdown = runStateAtLeast(c, SHUTDOWN);     # rs >= SHUTDOWN(0)
          boolean atLeastStop = runStateAtLeast(c, STOP) || firstTask != null || workQueue.isEmpty();    
          if (atLeastShutdown && atLeastStop){
                         return false;
           }
       工作流程注意点:
            Worker实例创建的同时,在其构造函数中会通过ThreadFactory创建一个Java线程Thread实例,
            后面会加锁后二次检查是否需要把Worker实例添加到工作线程集合workers中和是否需要启动Worker中持有的Thread实例,
            只有启动了Thread实例实例,Worker才真正开始运作,否则只是一个无用的临时对象。Worker本身也实现了Runnable接口,
            它可以看成是一个Runnable的适配器。

  

学习来源:https://www.cnblogs.com/throwable/p/13574306.html

posted @ 2020-09-02 16:13  小窝蜗  阅读(401)  评论(0编辑  收藏  举报