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<<29 = 11100000 00000000 00000000 (左移29位, 移动多少位, 后面补多少个0, 高于32位的去掉)。

各个state:

-1<<29 = 11100000 00000000 00000000   =>  RUNNINGZ

0<< 29 = 00000000 00000000 00000000   =>  SHUTDOWN

1 <<29 = 00100000 00000000 00000000   =>  STOP

2 <<29 = 01000000 00000000 00000000   =>  TIDYING

3 <<29 = 01100000 00000000 00000000   =>  TERMINATED

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

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

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

再看CAPACITY = (1<<29) -1:

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

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

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

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

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

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

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

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

11100000 00000000 00000000 | 00000000 00000000 00000000 = 11100000 00000000 00000000

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

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

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

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

CAPACITY = (1<<29)- 1 = 00100000 00000000 00000000 - 1 = 00011111 11111111 11111111

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

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

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

c &~CAPACITY =00100000 00000000 00000011 & 11100000 00000000 00000000 = 00100000 00000000 00000000,

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

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

线程池:ThreadPoolExcutor源码阅读的更多相关文章

  1. 深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  2. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  3. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

  4. linux线程池thrmgr源码解析

    linux线程池thrmgr源码解析 1         thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2      ...

  5. Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析

    目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...

  6. 一个python线程池的源码解析

    python为了方便人们编程高度封装了很多东西,比如进程里的进程池,大大方便了人们编程的效率,但是默认却没有线程池,本人前段时间整理出一个线程池,并进行了简单的解析和注释,本人水平有限,如有错误希望高 ...

  7. Java调度线程池ScheduledThreadPoolExecutor源码分析

    最近新接手的项目里大量使用了ScheduledThreadPoolExecutor类去执行一些定时任务,之前一直没有机会研究这个类的源码,这次趁着机会好好研读一下. 该类主要还是基于ThreadPoo ...

  8. [转载] Java线程池框架源码分析

    转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...

  9. 线程池ThreadPoolExecutor源码解读研究(JDK1.8)

    一.什么是线程池 为什么要使用线程池?在多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程 ...

随机推荐

  1. 巧用 background-clip 实现超强的文字动效

    最近,有同学询问,如何使用 CSS 实现如下效果: 看起来是个很有意思的动效. 仔细思考一下,要想实现这类效果,其实用到的核心属性只有一个 -- background-clip: text. 有意思的 ...

  2. VS Code失焦时自动保存编辑器内容

    vs code有一个非常好用的功能:就是自动保存. 而且不需要安装什么插件,只需要在编辑器设置就可以了.接下来我们一起来设置吧: 1.打开我们的vs code编辑器.在左下角有个  齿轮图标(管理), ...

  3. 1903021116-吉琛-Java第四周作业-程序编写

    项目 内容 课程班级博客链接 19级信计班 这个作业要求链接 Java分支语句学习 https://edu.cnblogs.com/campus/pexy/19xj/homework/12563 我的 ...

  4. AngularJS性能优化心得,自己踩过的抗,及一些别人的经验(转哦)

    脏数据检查 != 轮询检查更新 谈起angular的脏检查机制(dirty-checking), 常见的误解就是认为: ng是定时轮询去检查model是否变更.其实,ng只有在指定事件触发后,才进入$ ...

  5. C# 中托管内存与非托管内存之间的转换

    c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...

  6. KTL 一个支持C++14编辑公式的K线技术工具平台 - 第五版,支持sqlite3,全新sqlite3zz语法超简单使用sqlite3; 添加方差等统计函数。

    K,K线,Candle蜡烛图. T,技术分析,工具平台 L,公式Language语言使用c++14,Lite小巧简易. 项目仓库:https://github.com/bbqz007/KTL 国内仓库 ...

  7. 安装黑苹果 、 Mac OS虚拟机

    Mac OS 虚拟机 所需文件地址 unlocker 为VMware 新增Apple Mac OS X操作系统 Install_macOS_Monterey_12.0.1_21A559.iso 提取码 ...

  8. Django与socket

    Web框架本质是socket 各种socket一般都遵循wsgi协议 Django里面没有socket Django映射到Web框架,用了一个别人的socket:wsgiref 所以:django默认 ...

  9. javaScript中Math内置对象基本方法入门

    概念 Math 是javaScript的内置对象,包含了部分数学常数属性和数学函数方法. Math 不是一个函数对象,用户Number类型进行使用,不支持BigInt. Math 的所有属性与方法都是 ...

  10. 【CSAPP】Bomb Lab实验笔记

    bomblab这节搞的是二进制拆弹,可以通俗理解为利用反汇编知识找出程序的六个解锁密码. 早就听闻BOMBLAB的大名,再加上我一直觉得反汇编是个很艰难的工作,开工前我做好了打BOSS心理准备.实际上 ...