系列目录

线程数量的维护

线程池的大小有两个重要的参数,一个是corePoolSize(核心线程池大小),另一个是maximumPoolSize(最大线程大小)。线程池主要根据这两个参数对线程池中线程的数量进行维护。

需要注意的是,线程池创建之初是没有任何可用线程的。只有在有任务到达后,才开始创建线程,并复用线程。

注:此图不是状态图,不是说添加一个线程就直接到达corePoolSize状态,而是要表示,一直添加线程直到达到corePoolSize。

注释里也写的很清楚了:

(1)如果线程数未达核心数,则每接收一个任务就创建一个工作线程(这里把Worker视为工作线程)来处理。

(2)如果线程数已达到核心数,那就把任务先放入队列。等到有工作线程完成任务了,会自行从队列中取任务做。

(3)如果任务无法放入队列,如队列是有界队列,且已满。那么就会继续创建工作线程来处理这个任务。注意,这里的新线程已经不是核心线程了。

(4)如果线程数量已经达到maxPoolSize,这时候就是线程不能再创建了,任务也放不进队列了,就得启动reject策略。默认策略是AbortPolicy,也就是直接报异常。

public void execute(Runnable command) {
//非空检查
if (command == null)
throw new NullPointerException(); //获取线程池控制信息
int c = ctl.get();
//通过workerCountOf方法获取控制信息内的工作线程数信息
//如果小于核心线程数,执行addWorker方法 0 => corePoolSize
if (workerCountOf(c) < corePoolSize) {
//这个操作添加的是核心工作线程,且有初始任务
if (addWorker(command, true))
return; //如果操作成功直接返回
//由于addWorker操作对工作线程数,可能有所更改,故重新获取控制信息
c = ctl.get();
} //添加核心线程失效后
//如果线程池处于运行状态,且任务成功加入阻塞队列 corePoolSize => corePoolSize
if (isRunning(c) && workQueue.offer(command)) {
//再次检查线程池状态
int recheck = ctl.get();
//如果线程池处于非运行状态,则把刚刚加入队列的任务移除
if (! isRunning(recheck) && remove(command))
//执行拒绝策略
reject(command);
//当前没有工作者线程,则添加非核心线程
else if (workerCountOf(recheck) == )
addWorker(null, false);
}
//如果任务未能加入阻塞队列,则添加非核心线程 corePoolSize => maxPoolSize
//如果添加非核心线程也失败,开启拒绝策略
else if (!addWorker(command, false))
reject(command); //maxPoolSize => maxPoolSize
}

【详解】ThreadPoolExecutor源码阅读(三)的更多相关文章

  1. 【详解】ThreadPoolExecutor源码阅读(二)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) AQS在W ...

  2. 【详解】ThreadPoolExecutor源码阅读(一)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) 工作原理简 ...

  3. Android应用AsyncTask处理机制详解及源码分析

    1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机 ...

  4. 【转载】Android应用AsyncTask处理机制详解及源码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个 ...

  5. 线程池底层原理详解与源码分析(补充部分---ScheduledThreadPoolExecutor类分析)

    [1]前言 本篇幅是对 线程池底层原理详解与源码分析  的补充,默认你已经看完了上一篇对ThreadPoolExecutor类有了足够的了解. [2]ScheduledThreadPoolExecut ...

  6. 基于双向BiLstm神经网络的中文分词详解及源码

    基于双向BiLstm神经网络的中文分词详解及源码 基于双向BiLstm神经网络的中文分词详解及源码 1 标注序列 2 训练网络 3 Viterbi算法求解最优路径 4 keras代码讲解 最后 源代码 ...

  7. Java SPI机制实战详解及源码分析

    背景介绍 提起SPI机制,可能很多人不太熟悉,它是由JDK直接提供的,全称为:Service Provider Interface.而在平时的使用过程中也很少遇到,但如果你阅读一些框架的源码时,会发现 ...

  8. select用法&原理详解(源码剖析)(转)

    今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...

  9. 详解ConCurrentHashMap源码(jdk1.8)

    ConCurrentHashMap是一个支持高并发集合,常用的集合之一,在jdk1.8中ConCurrentHashMap的结构和操作和HashMap都很类似: 数据结构基于数组+链表/红黑树. ge ...

随机推荐

  1. MySQL查询练习(45道)

    题目:设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher). 四个表的结构分别如表1-1的表(一)~表(四)所示,数据如表1 ...

  2. spring-事件通知实现

    ok,今天不知道看啥来着,突然想起来spring内部的事件通知的实现,其实比较简单,简要记一下.然后又回顾了下eventbus的实现,其实俩者的实现方式大同小异吧,只是spring的很多操作都可以直接 ...

  3. ETL化的IOTA架构

    经过这么多年的发展,已经从大数据1.0的BI/Datawarehouse时代,经过大数据2.0的Web/APP过渡,进入到了IOT的大数据3.0时代,而随之而来的是数据架构的变化. ▌Lambda架构 ...

  4. python_运算符与表达式

    运算符与表达式 python运算符 运算符 功能说明 + 算术加法,列表.元组.字符串合并与连接,正号 - 算术减法,集合差集,相反数 * 算术乘法,序列重复 / 真除法 // 求整商,但如果操作数中 ...

  5. file新建文件及文件夹

    1.获取包名的根目录:mRootPath = getFilesDir().getParent(); // ====mRootPath===/data/data/com.yoyu.file  获取SD卡 ...

  6. hive sql 查询一张表的数据不在另一张表中

    有时,我们需要对比两张表的数据,找到在其中一张表,不在另一张表中的数据 hql 如下: SELECT * FROM (SELECT id FROM a WHERE dt = '2019-03-17' ...

  7. 知物由学 | AI在Facebook清理有害内容上扮演了什么角色?

    "知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道."知物 ...

  8. Android Parcelable using Kotlin

    Kotlin 有 extension 可以很方便的让类继承 Parcelable 接口. 项目中引入一个较新版本的 Kotlin 引入 Kotlin extensions classpath &quo ...

  9. Linux Shell脚本编程基础(11)

    实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核,不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序.Shel编程语言具有普通编程 ...

  10. 面向对象三大特性编写面向对象程序,self到底是谁

    一.函数式编程和面向对象的对比 面向过程:根据业务逻辑从上到下写垒代码: 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可: 面向对象:对函数进行分类和封装,让开发“更快更好更强. ...