线程池: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<<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源码阅读的更多相关文章
- 深入浅出Java线程池:源码篇
前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...
- Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析
目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...
- java线程池ThreadPoolExector源码分析
java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...
- linux线程池thrmgr源码解析
linux线程池thrmgr源码解析 1 thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2 ...
- Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析
目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...
- 一个python线程池的源码解析
python为了方便人们编程高度封装了很多东西,比如进程里的进程池,大大方便了人们编程的效率,但是默认却没有线程池,本人前段时间整理出一个线程池,并进行了简单的解析和注释,本人水平有限,如有错误希望高 ...
- Java调度线程池ScheduledThreadPoolExecutor源码分析
最近新接手的项目里大量使用了ScheduledThreadPoolExecutor类去执行一些定时任务,之前一直没有机会研究这个类的源码,这次趁着机会好好研读一下. 该类主要还是基于ThreadPoo ...
- [转载] Java线程池框架源码分析
转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...
- 线程池ThreadPoolExecutor源码解读研究(JDK1.8)
一.什么是线程池 为什么要使用线程池?在多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程 ...
随机推荐
- Mycat管理
Mycat 提供了类似数据库的管理监控方式,可以通过 mycat 端口 9066 执行相应的 SQL 语句进行管理,可以可以通过 navicat 软件进行远程连接管理,再使用 MySQL 命令行界面登 ...
- Vue基础二之全局API、实例属性和全局配置,以及组件进阶(mixins)的详细教程(案列实现,详细图解,附源码)
本篇文章主要是写Vue.directive().Vue.use()等常用全局API的使用,vm.$props.vm.$options.vm.$slots等实例属性的使用,以及Vue全局配置.组件的mi ...
- clickhouse智能提示编辑器
对于经常写sql的人来说智能提示是非常重要的,这个非常影响写sql的效率和心情. 这里说的智能提示不仅仅是关键字(select等)的智能提示,还得要做到表字段的智能提示. 例如: 下面是mysql的智 ...
- JavaWeb入门day9-随笔(session/cookie)
会话 一个网站怎么证明用户访问过 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以:cookie 服务器登记,下次访问匹配:session 保存会话的技术 cookie 客户端技术(响应.请 ...
- innodb源码解析 - mem0_.c - 基本内存管理
The basic element of the memory management is called a memoryheap. A memory heap is conceptually ast ...
- 多线程的创建,并发,静态代理,Lambda表达式
程序是指令和数据的有序集合,本身没有任何运行的含义.是一个静态的概念. 在操作系统中运行的程序就是进程(Process),如:QQ,播放器,游戏等等. 进程是程序的一次执行过程,是一个动态的概念,是系 ...
- 【阿里巴巴Java开发手册1.7.0(嵩山版)】编程规约&MySQL 数据库规约
阿里巴巴Java开发手册1.7.0(嵩山版) 一.编程规约 (一)命名风格 所有命名不得以下划线和$开始和结束. 所有命名不得以拼音或拼音英文混合. 类名使用UpperCamelCase风格. 方法名 ...
- HMS Core Discovery第14期回顾长文|纵享丝滑剪辑,释放视频创作力
HMS Core Discovery第14期直播<纵享丝滑剪辑,释放视频创作力>,已于4月21日圆满结束,本期直播我们同HMS Core视频编辑服务(Video Editor Kit)的产 ...
- input输入框自动填充的问题
火狐浏览器打开页面,input可以自动填充历史输入值,现在想无论input类型是type='text'还是'password'都禁止自动填充,因为我写的页面在input='text'时先检查是否有输入 ...
- 浅尝Spring注解开发_Bean生命周期及执行过程
Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含Bean生命周期.自定义初始化方法.Debug BeanPostProcessor执行过程及在Spring底层中的应 ...