【源码笔记】ThreadPoolExecutor#getTask

/**
 * Performs blocking or timed wait for a task, depending on
 * current configuration settings, or returns null if this worker
 * must exit because of any of:
 * 1. There are more than maximumPoolSize workers (due to
 *    a call to setMaximumPoolSize).

 * 2. The pool is stopped.

 * 3. The pool is shutdown and the queue is empty.

 * 4. This worker timed out waiting for a task, and timed-out
 *    workers are subject to termination (that is,
 *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
 *    both before and after the timed wait, and if the queue is
 *    non-empty, this worker is not the last thread in the pool.

 *
 * @return task, or null if the worker must exit, in which case
 *         workerCount is decremented
 */
// 什么情况下会返回null?
// 1.rs >= STOP
// 2.SHUTDOWN && workQueue.isEmpty()
// 3.线程池中的线程数超过最大限制时,会有一部分线程返回null
//   wc > maximumPoolSize && (wc > 1 || workQueue.isEmpty())
// 4.线程池中的线程数超过corePoolSize时,会有一部分线程返回null
//   (timed && timedOut) && (wc > 1 || workQueue.isEmpty())
private Runnable getTask() {
    // 当前线程获取任务是否超时
    boolean timedOut = false; // Did the last poll() time out?

    // 自旋
    for (;;) {
        // 获取最新ctl的值
        int c = ctl.get();
        // 获取线程池当前运行状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.

        // 条件1.rs >= SHUTDOWN
        //   true --> 当前线程池状态不为running
        // 条件2.(rs >= STOP || workQueue.isEmpty())
        //   条件2.1 rs >= STOP
        //     true --> 当前线程池的状态最低也是stop了,则getTask会失败
        //   条件2.2 workQueue.isEmpty()
        //     前置条件:线程池的状态是SHUTDOWN
        //     true --> queue为空,则getTask会失败
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 返回null,runWorker就会将返回值为null的线程执行退出线程池的逻辑
            // worker count减一(CAS+自旋)
            decrementWorkerCount();
            return null;
        }

        // 执行到这里,有两种情况:
        // 1. 线程池状态是RUNNING
        // 2. 线程池状态是SHUTDOWN,且queue不为空
        // 只有这两种情况可以创建线程

        // 获取到worker的数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?

        // 条件:allowCoreThreadTimeOut || wc > corePoolSize
        //   true --> 当前线程池获取线程支持超时机制,queue.poll(xxx,xxx);在获取task超时的情况下,下一次自旋可能就返回null了
        //   false -> 当前线程池获取线程不支持超时机制的。当前线程会使用queue.take()
        // allowCoreThreadTimeOut 是否允许核心线程超时
        // - 若为true,则说明不论那种线程,获取task的时候都要加入超时机制
        // - 若为false,则获取核心线程的任务不允许超时,但是获取非核心线程的任务加入超时机制
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // 条件1.(wc > maximumPoolSize || (timed && timedOut))
        //   条件1.1 wc > maximumPoolSize 可能会成立的原因:
        //     外部线程调用了setMaximumPoolSize方法,将线程池最大线程数设置为比初始化的时候要小
        //   条件1.2 timed && timedOut
        //     有超时机制,且上一次循环时,使用poll方式获取任务时,超时了
        // 条件1代表,线程达到了回收的标准,可以被回收。等确实需要回首时再回收
        // 条件2.(wc > 1 || workQueue.isEmpty())
        //   条件2.1 wc > 1
        //     true --> 说明线程池中还有其它线程,当前线程可以直接回收 --> 返回null
        //   条件2.2 workQueue.isEmpty()
        //     前置条件:wc == 1
        //     true --> 说明当前任务队列已经空了,最后一个线程也可以放心退出
        //
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 使用CAS的方式让workerCount减一
            // CAS成功的线程返回null
            // CAS失败的线程continue自旋
            //   CAS失败的原因:1.其它线程先减了数量;2.线程池的状态发生了变化
            if (compareAndDecrementWorkerCount(c))
                return null;

            // 再次自旋时,timed可能为false
            // 因为当前线程CAS失败,可能是因为其它线程成功退出导致的
            // 再次自旋时,wc  即属于不需要回收的范围内了
            continue;
        }

        // 以下为获取任务的逻辑

        try {
            // 获取任务
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();

            // 任务不为null,返回任务
            if (r != null)
                return r;
            // 执行到这里,获取任务超时了(如果不为null,则已经返回了;为null,则说明获取task超时)
            // 下一次自旋的时候,可能就会返回null了
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

Original: https://www.cnblogs.com/daheww/p/16728990.html
Author: daheww
Title: 【源码笔记】ThreadPoolExecutor#getTask

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/713269/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 常用开发工具的安装和使用

    常用开发工具的安装和使用 IntelliJ IDEA的安装和使用 安装教程 1.教育优惠 JetBrains开发的众多开发工具提供教育优惠,可以方便在校学生使用。通过学校提供的教育…

    技术杂谈 2023年7月23日
    084
  • 网络设备配置-8、利用ospf配置动态路由

    一、前言 同系列前几篇:网络设备配置–1、配置交换机enable、console、telnet密码网络设备配置–2、通过交换机划分vlan网络设备配置&#8…

    技术杂谈 2023年7月11日
    060
  • Web开发静态资源处理

    Web开发静态资源处理 7.1 静态资源处理 我们要引入前端资源,项目中有许多的静态资源,比如css,js等文件,这个SpringBoot是怎么处理呢? 如果我们是一个web应用,…

    技术杂谈 2023年6月21日
    097
  • 构建基于React18的电子表格程序

    背景 2022年3月29日,React正式发布18.0.0。本次升级内容包括开箱即用的改进,如自动批处理、新的API(如startTransition)和支持Suspense 的流…

    技术杂谈 2023年5月31日
    0107
  • 观测下老外的水平如何

    I’m not exactly sure what you are trying to achieve here. Whatever you transceive wi…

    技术杂谈 2023年5月31日
    070
  • hdu 1845

    一看题意就是二分匹配问题,建边是双向的,两个集合都是n个点 这题的图很特殊,每个点都要与三个点相连,在纸上画了六个点的图就感觉此图最大匹配肯定是六,除以2就是原图的匹配了,就感觉这…

    技术杂谈 2023年6月1日
    090
  • 书评写作的4步骤7要点

    第一步,选书。 就是你要选什么样的书? 可以选评分高的书,比如豆瓣评分7分以上的书,看了好书才有好内容可写。 可以选你自己喜欢或者感兴趣的书,因为你喜欢才能有触动有感想。 可以选与…

    技术杂谈 2023年6月1日
    097
  • [教程] 【亲测可用】阿里云盘挂载变成你的电脑本地硬盘详细教程

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    技术杂谈 2023年5月31日
    0105
  • 《Microsoft Teams平台完全手册》开工

    上个月,因为一些意外情况,博客园曾经一度无法发布文章,博客园团队日夜奋战解决问题。他们的努力,和坚持,不见得每个人都理解,我是深表敬意的。 最近,我又开始写一本书稿,是关于Micr…

    技术杂谈 2023年5月31日
    081
  • 圆方图(铁人两项)

    #include using namespace std; const int MM=400005; int dfn[MM],low[MM],dfc,cnt,in[MM],tot,…

    技术杂谈 2023年6月21日
    082
  • Weblogic页面应用查询oracle数据库后台报错或页面日期格式显示错误

    问题:在生产环境中有两台WEB服务器,分别为227和228,部署的应用代码都是每日同步的,两边完全一致,但是某些页面查询数据时,227无结果,并且后台报java数组越界的错误,而2…

    技术杂谈 2023年7月11日
    070
  • JAVA WEB 中的编码分析

    ServletPath和PathInfo中的中文 QueryString中的中文 public void service(org.apache.coyote.Request req…

    技术杂谈 2023年7月24日
    056
  • 心态崩了,我怎么知道实际生产环境的 B+ 树索引有多少层?

    Q:在实际生产环境中,InnoDB 中一棵 B+ 树索引一般有多少层?可以存放多少行数据? 关于这个问题最近好像在牛客上经常看到,感觉没啥意义,可能主要考察的是对 B+ 索引的理解…

    技术杂谈 2023年7月25日
    0105
  • X-Y问题

    什么是X-Y问题 X-Y问题就是有人想解决问题X,他觉得Y可能是解决X的方法但不知道Y怎么做;在我们的工作中,需求方给出的来的是Y,而软件工程师不知道需要解决的X是什么。 我理解的…

    技术杂谈 2023年7月25日
    063
  • 【转】OC-音乐播放器-锁屏处理

    QQ音乐播放的过程中,锁屏状态下的效果如下: 也就是说,QQ音乐播放过程中,添加锁屏远程事件的监听。 本文只记录本人知道的小知识点,不提供完整的代码。 实现的原理: (1)获取锁屏…

    技术杂谈 2023年6月1日
    082
  • linux多线程-使用mmap映射实现文件拷贝

    一、代码实现思路 1、示意图 2、示意图注解 循环创建i个线程,将src文件分为i段拷贝到dest文件中 (1)src文件的大小为src_size,前i-1个线程拷贝的文件大小为s…

    技术杂谈 2023年7月11日
    058
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球