线程池:ThreadPoolExcutor源码阅读

ThreadPoolExcutor源码流程图:(图片较大,下载再看比较方便)

线程池:ThreadPoolExcutor源码阅读

线程池里的二进制奥秘

前言:

线程池的五种状态state (RUNNING 、SHUTDOWN 、STOP 、TIDYING 、TERMINATED )和线程池的工作线程数:workerCount,

这两个变量,可有通过一个变量ctl 转成二进制后而获得。

直接看线程池ThreadPoolExecutor 源码里,管理状态和工作线程数的代码

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

Integer.size 为Integer 类型最大值的二进制的位数:32 (位),COUNT_BITS = 29 (位),为啥是要要减去3 ,拿个29 呢,因为它想用二进制高3 位来表示线程池的状态(state ),后面的29 位用来表示工作线程数量(workerCount )。

比如RUNNINGZ 状态是-1 左移29 位,即:

-1 的二进制算法,先取绝对值1 的二进制:00000000 00000000 00000001 ,再取反码:11111111 11111111 11111110

再取补码(加1 ):11111111 11111111 11111111 ,这就是-1 的二进制表示。

左移运算:-1<

各个state :

-1<

0<< 29 =000 00000 00000000 00000000 => SHUTDOWN

1 <

2 <

3 <

线程池就是这样用高三位来表示不同的状态。

所以状态还有这样的关系: RUNNINGZ < SHUTDOWN < STOP < TIDYING < TERMINATED

不管各个状态低29 位是啥,这个关系都不会变。

再看CAPACITY = (1<

即00100000 00000000 00000000 – 1 = 00011111 11111111 11111111 ,这是线程池最大容量线程数(536870911 ),

即是用1 到29 位可表示线程的数量,那么,ctl = state.高3 位+低29 位,如:

ctl =111 11111 11111111 11111111 ,表示线程池是RUNNINGZ 状态,且线程数为536870911 ;

ctl =000 00000 00000000 00000001 ,表示线程池是SHUTDOWN 状态,且线程数为1 ;

CAPACITY=536870911 ,表示线程池最大线程数容量为536870911 ,但这个最大数值可以忽略,

因为在实例化线程池的时候,已经通过传参数设置了核心线程数、允许最大线程数。

初始化为 ctl = new AtomicInteger(ctlOf (RUNNING, 0));

ctlOf (RUNNING, 0)参数中的0 ,意思是初始化线程池的线程数为0 。然后通过ctlOf做或运算,即:

111 00000 00000000 00000000 | 00000000 00000000 00000000 =111 00000 00000000 00000000

运算后的结果,把表示状态的高3 位、表示线程数的低29 位组合起来得到一个数ctl ,

下次拿到ctl 之后,就知道此时线程池的状态和线程数量了。

1、那么runStateOf(int c)方法具体是怎么知道线程池的状态的?

假设c = ctl.get() =001 00000 00000000 00000011 ,表示STOP 状态且还有3 个线程

CAPACITY =(1<

为啥要减1 呢?因为减1 后:

1 、把表示状态的高3 位给挪留出来了,值又可以表示线程池最大线程数。

2 、把表示线程数的低29 位变为了1 ,那~CAPACITY = 11100000 00000000 00000000 , 所以:

c &~CAPACITY =001 00000 00000000 00000011 & 11100000 00000000 00000000 =001 00000 00000000 00000000 ,

结果001 00000 00000000 00000000 保持c 的高3 位不变,把c 的低29 位全变成0,这就是获得线程池是STOP 状态

2、通过workerCountOf(int c)获取工作线程数,同上理

Original: https://www.cnblogs.com/incognitor/p/16401160.html
Author: 無名之徒
Title: 线程池:ThreadPoolExcutor源码阅读

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

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

(0)

大家都在看

  • Python第二十一天 fileinput模块

    Python第二十一天 fileinput模块 fileinput模块 fileinput.input([files[, inplace[, backup[, bufsize[, …

    数据库 2023年6月9日
    062
  • Mysql数据库存取原理及性能优化

    一、Mysql的系统架构图 二、Mysql存储引擎 Mysql中的数据是通过一定的方式存储在文件或者内存中的,任何方式都有不同的存储、查找和更新机制,这意味着选择不同的方式对于数据…

    数据库 2023年6月14日
    091
  • openpyxl使用总结

    设置表头单元格的颜色 fill = PatternFill("solid", fgColor=’FF000000′) font = Font(color=’00…

    数据库 2023年6月9日
    070
  • 我说MySQL联合索引遵循最左前缀匹配原则,面试官让我回去等通知

    面试官: 我看你的简历上写着 精通MySQL,问你个简单的问题, MySQL联合索引有什么特性? 心想,这还不简单,这不是问到我手心里了吗?听我给你背一遍八股文! 我: MySQL…

    数据库 2023年5月24日
    074
  • 基于 ZooKeeper 的分布式锁实现

    ZK 基本概念 apache hadoop 下面的子项目,是一个树形目录服务 字面意思就是动物管理员,诞生之初用来管理 hadoop(大象)、Hive(蜜蜂)、Pig(小猪) 用于…

    数据库 2023年6月6日
    077
  • CPU 是如何与内存交互的

    这篇文章主要整理了一下计算机中的内存结构,以及 CPU 是如何读写内存中的数据的,如何维护 CPU 缓存中的数据一致性。什么是虚拟内存,以及它存在的必要性。如有不对请多多指教。 概…

    数据库 2023年6月14日
    079
  • 一个线程的打工故事

    前言 前几天小强去阿里巴巴面试Java岗,止步于二面。 他和我诉苦自己被虐的多惨多惨,特别是深挖线程和线程池的时候,居然被问到不知道如何作答。 对于他的遭遇,结合他过了一面的那个嘚…

    数据库 2023年6月16日
    0120
  • MySQL设计表结构

    时间datetime 创建时间不能自动更新,更新时间需要自动更新 CURRENT_TIMESTAMP:创建时,会用当前时间自动填充该字段值 CURRENT_TIMESTAMP ON…

    数据库 2023年6月9日
    074
  • leetcode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树) (中等)

    Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼…

    数据库 2023年6月16日
    089
  • Java中如何数组进行反转呢?

    下文笔者将讲述java代码数组反转的方法分享,如下所示: 数组是我们日常开发中常用过的一种数据结构,那么我们如何将一个数组反转操作呢? 下文笔者借助栈对象的先进后出的特性, 首先将…

    数据库 2023年6月11日
    067
  • Linux 系统安装RocketMQ

    准备工作 1.去官网下载一个安装包 1.解压 unzip rocketmq-all-4.9.0-bin-release.zip -d /download/compress/ 2.进…

    数据库 2023年6月6日
    077
  • 学习笔记——Django项目中的请求

    2022-10-03 url中的位置参数 位置参数存放的位置 是子应用中的自定义的”urls.py”文件中的路由中。 位置参数的设置: 如果位置参数很多,那…

    数据库 2023年6月14日
    048
  • mysql中all用法和any的用法和内连接和外连接,全外连接,联合查询,自连接

    与子查询配合使用 在all的用法中,有三种 语法:select 列名 from 表名 where 列名 <> all(select 列名 from 表名 where 条…

    数据库 2023年6月16日
    076
  • mysql数据库创建数据库创建用户授权

    Liunx下登录数据库 mysql -u 用户名 -p 创建myblog用户,本地登录,口令是myblog create user ‘myblog’@&#8…

    数据库 2023年6月11日
    078
  • Shell 第二章《流控》

    前言 无论什么编程语言都离不开条件判断(流控)。SHELL也不例外。例如,用户输入的密码不够长时提示用户,你太短了例如,用户输入了备份的目录,如果有目录继续备份,如果没有目录创建目…

    数据库 2023年6月14日
    082
  • 01-MySQL主从复制

    问题导入 在之前项目的基础功能实现中,后台管理和移动端在进行数据访问的时候,都是直接操作数据库MySQL。此时的系统有且仅有一台MySQL服务器,则可能会出现如下问题 ①、读和写所…

    数据库 2023年5月24日
    065
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球