前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >源码解析:ThreadPoolExecutor(5)

源码解析:ThreadPoolExecutor(5)

作者头像
爪哇缪斯
发布2023-05-09 21:47:30
1100
发布2023-05-09 21:47:30
举报
文章被收录于专栏:爪哇缪斯

3.4> 任务添加到队列的代码逻辑

  • 源码部分如下所示:

【解释】

  • 通过isRunning方法来判断线程池状态是不是运行中状态,如果是,则将command任务放到阻塞队列workQueue中。
  • 添加到阻塞队列成功后,还有一些后续操作。

比如:再次check一下,当前线程池是否是运行状态,如果不是运行时状态,则把刚刚添加到workQueue中的command移除掉,并调用拒绝策略。否则,判断如果当前活动的线程数如果为0,则表明只去创建线程,而此处,并不执行任务(因为,任务已经在上面的offer方法中被添加到了workQueue中了,等待线程池中的线程去消费队列中的任务)


3.5> 线程池中的线程数量小于最大线程数代码逻辑以及拒绝策略的代码逻辑

  • 源码部分如下所示:

【解释】

  • 由于调用addWorker的第二个参数是false,则表示对比的是最大线程数,那么如果往线程池中创建线程依然失败,即addWorker返回false,那么则进入if语句中,直接调用reject方法调用拒绝策略了。

四、 源码解析——addWorker(Runnable firstTask, boolean core)

  • 看完execute方法的源码解析,我们发现,代码里的逻辑判断就是我们在【1.2> 线程池工作流程】中讲解的那样。但是,这只是第一层代码的解析,关键的逻辑,其实都在第二层addWork代码中。下面我们就来解开addWorker的真面目。

4.1> 流程概述

  • addWorkder的流程图如下所示:

【解释】

  • 关于流程图中的绿色方块,我们会在后面的章节中展开介绍。
  • addWorkder的整个流程,其实可以分为两部分:
    • Part1(上图中红色框部分):试图将workerCount+1。
    • Part2(上图中蓝色框部分):workerCount成功+1后,创建Worker(也是一个Runnable),加入集合workers中,并启动Worker线程。

4.2> retry

  • 当我们打开addWorker方法的代码是,第一个映入眼帘的就是retry:
  • 其中,关于retry的详细讲解,我已经整理在公众号文章【面试题12:请介绍一下retry: 的用法】里面了,也有详细的例子。感兴趣的同学可以去这篇文章里看一下。与它相似用法在ConcurrentHashMap中也出现过,如下所示:

4.3> addWorkder的Part1解析

  • 我们先看一下Part1的源码和注释:
  • 在Part1中,首先还是从类型为AtomicInteger的ctl中获得最新值,然后调用runStateOf来获得当前线程池的运行状态。
  • 下面的if判断很长:if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())) ,理解这块我们其实需要以相反的判断去思考——也就是,如果if中的判断是false,那么就不用return false而可以继续往下执行了。那么,什么情况下,程序可以继续往下执行呢?
    • case1:如果线程池的状态时运行中(RUNNING),就可以继续往下执行了。
    • case2:如果线程池的状态时关闭(SHUTDOWN)并且firstTask=null并且阻塞队列workQueue中存在没有执行完毕的任务,那么就可以继续往下执行了。

也就是说,只有这两个情况,才不会直接返回false。还有继续往下执行的“机会”。

  • 代码在往下,就是一个无限的循环了,在循环里我们发现,如果线程池中的线程数等于或者超过了最大线程数量(CAPACITY),或者已经等于或者超越了核心线程数(corePoolSize)/最大线程数(maximumPoolSize),那么就会直接返回false,没有“机会”继续下去了。而具体是对比corePoolSize还是maximumPoolSize,是根据我们addWorker方法第二个入参boolean core来决定的。
  • 跳过这层阻碍,我们就要真正的去给当前的工作线程数加1了。这次依然采用的是CAS的方式去加1。如果加一成功,则Part1执行完毕,跳出循环,开始Part2的旅程。如果加一不成功,说明与其他线程操作冲突了,那么会重新获取最新的ctl值,再次循环执行上面的步骤。

后面的内容,参见:源码解析:ThreadPoolExecutor(6)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爪哇缪斯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.4> 任务添加到队列的代码逻辑
  • 3.5> 线程池中的线程数量小于最大线程数代码逻辑以及拒绝策略的代码逻辑
  • 四、 源码解析——addWorker(Runnable firstTask, boolean core)
    • 4.1> 流程概述
      • 4.2> retry
        • 4.3> addWorkder的Part1解析
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档