zoukankan      html  css  js  c++  java
  • 多线程笔记(三)线程池 ThreadPoolExecutor

    1. ctl:将 workerCount(工作线程的数量)和线程池的状态放在一个 int 中保存

        在 ctolOf 方法中实现

    private static int ctlOf(int rs, int wc) { return rs | wc; }

        作用:并不是节省空间,而是为了保持线程池状态和运行状态的统一,放在一个变量里,可以保证这两部分同时修改
    2. 五种状态,需要三个 bit 来表示,所以高 3 位表示状态,剩下的 29 位表示工作线程的数量,因此线程池中工作线程的最大数量为 $2^29−1$

        也就是 ThreadPoolExecutor.CAPACITY(高三位为 0,低 29 位为 1)

    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

        计算工作线程的数量:workerCountOf 方法。和 CAPACITY 做 & 运算,由于 CAPACITY 的低 29 位都为 1,所以可以取出工作线程的数量

    private static int workerCountOf(int c)  { return c & CAPACITY; }

        获取线程池状态:要取 ctl 的高三位的值,因此先把 CAPACITY 取反,然后和 ctl 做 & 运算

    private static int runStateOf(int c)     { return c & ~CAPACITY; }

    3. execute 方法

     1 public void execute(Runnable command) {
     2     if (command == null)
     3         throw new NullPointerException();
     4 
     5     // 获取当前线程池的状态
     6     int c = ctl.get();
     7     // 当工作线程数 < 核心线程池容量时,添加工作线程去执行任务
     8     if (workerCountOf(c) < corePoolSize) {
     9         if (addWorker(command, true))
    10             return;
    11         // 重新获取状态
    12         c = ctl.get();
    13     }
    14     // 达到核心池上限,尝试加入缓存队列
    15     if (isRunning(c) && workQueue.offer(command)) {
    16         int recheck = ctl.get();
    17         // 再次检查线程池状态
    18         if (! isRunning(recheck) && remove(command))// 线程池没有在运行,将任务移出队列,并执行拒绝策略
    19             reject(command);
    20         else if (workerCountOf(recheck) == 0)// 线程池中没有线程,需要创建新的线程,传入 null 是因为创建的线程去队列里取任务,不需要指定执行的任务
    21             addWorker(null, false);
    22     }
    23     else if (!addWorker(command, false)) // 缓存队列已满,尝试创建新的线程
    24         reject(command);
    25 }

    4. addWorker 方法

     1 private boolean addWorker(Runnable firstTask, boolean core) {
     2     retry:
     3     for (;;) { // loop1
     4         int c = ctl.get();
     5         int rs = runStateOf(c);
     6 
     7         // Check if queue empty only if necessary.
     8         // 此处 if 判断为 False 只有两种情况:rs 为 running(也就是 < shutdown),当然可以继续添加线程;还有就是虽然线程池已经 shutdown,但是不会添加新的任务(firstTask == null),同时队列里还有任务,也就是(rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()),其他情况都是 True,需要停止添加线程,返回 false
     9         if (rs >= SHUTDOWN &&
    10             ! (rs == SHUTDOWN &&
    11                firstTask == null &&
    12                ! workQueue.isEmpty()))
    13             return false;
    14 
    15         for (;;) {
    16             int wc = workerCountOf(c);
    17             if (wc >= CAPACITY ||
    18                 wc >= (core ? corePoolSize : maximumPoolSize))
    19                 return false;
    20             // CAS 使 workCount 加 1,成功则退出 loop1,继续下面的代码
    21             if (compareAndIncrementWorkerCount(c))
    22                 break retry;
    23             c = ctl.get();  // Re-read ctl
    24             // CAS 操作失败,重新检查状态,如果线程池状态改变,进行外部循环(loop1)
    25             if (runStateOf(c) != rs)
    26                 continue retry;
    27             // else CAS failed due to workerCount change; retry inner loop
    28             // 线程池状态不变的话,继续内部循环,尝试使 workCount 加 1
    29         }
    30     }
    31 
    32     boolean workerStarted = false;
    33     boolean workerAdded = false;
    34     Worker w = null;
    35     try {
    36         // 创建新线程
    37         w = new Worker(firstTask);
    38         final Thread t = w.thread;
    39         if (t != null) {
    40             final ReentrantLock mainLock = this.mainLock;
    41             mainLock.lock();
    42             try {
    43                 // Recheck while holding lock.
    44                 // Back out on ThreadFactory failure or if
    45                 // shut down before lock acquired.
    46                 int rs = runStateOf(ctl.get());
    47                 
    48                 // 检查线程池状态
    49                 if (rs < SHUTDOWN ||
    50                     (rs == SHUTDOWN && firstTask == null)) {
    51                     if (t.isAlive()) // precheck that t is startable
    52                         throw new IllegalThreadStateException();
    53                     workers.add(w);
    54                     int s = workers.size();
    55                     if (s > largestPoolSize)
    56                         largestPoolSize = s;
    57                     workerAdded = true;
    58                 }
    59             } finally {
    60                 mainLock.unlock();
    61             }
    62             if (workerAdded) {
    63                 // 启动线程
    64                 t.start();
    65                 workerStarted = true;
    66             }
    67         }
    68     } finally {
    69         if (! workerStarted)
    70             addWorkerFailed(w);
    71     }
    72     return workerStarted;
    73 }
  • 相关阅读:
    修改大表结构注意事项
    短信猫 Mysql ODBC问题
    各互联网公司UDE分享
    MySQL 取分类后的前n条
    批处理当前日期
    Fixed Event Scheduler No data zero rows fetched, selected, or processed
    数据库设计注意事项
    本月,下一月, 上一月 的 1号, 最后一号
    自动化测试编程语言的选择
    QTP描述编程中使用正则表达式
  • 原文地址:https://www.cnblogs.com/ainsliaea/p/11372763.html
Copyright © 2011-2022 走看看