前言

在之前阅读 ThreadPoolExecutor 源码的时候,发现代码里用到了一些二进制相关的位运算之类的代码,看起来有些费劲了,所以现在大概总结了一些笔记,二进制这东西吧,不难,就跟数学一样,知道规律,计算公式,就贼简单,就是二进制转十进制这种自己算起来比较费劲

但现在又不是考试,所以我选择计算器!!!!

二进制

计算机采用二进制原因:

  • 首先,二进位计数制仅用两个数码。0和1,所以,任何具有二个不同稳定状态的元件都可用来表示数的某一位。而在实际上具有两种明显稳定状态的元件很多。例如,氖灯的;开关的; 电压的;纸带上的有孔无孔,电路中的有信号无信号, 磁性材料的南极北极等等,不胜枚举。 利用这些截然不同的状态来代表数字,是很容易实现的。不仅如此,更重要的是两种截然不同的状态不单有量上的差别,而且是有质上的不同。这样就能大大提高机器的抗干扰能力,提高可靠性。而要找出一个能表示多于二种状态而且简单可靠的器件,就困难得多了。
  • 其次,二进位计数制的四则运算规则十分简单。而且四则运算最后都可归结为加法运算和移位,这样,电子计算机中的运算器线路也变得十分简单了。不仅如此,线路简化了,速度也就可以提高。这也是十进位计数制所不能相比的 。
  • 第三,在电子计算机中采用二进制表示数可以节省设备。可 以从理论上证明,用三进位制最省设备,其次就是二进位制。但由于二进位制有包括三进位制在内的其他进位制所没有的优点,所以大多数电子计算机还是采用二进制。此外,由于二进制中只用二个符号 “ 0” 和“1”,因而可用布尔代数来分析和综合机器中的逻辑线路。 这为设计电子计算机线路提供了一个很有用的工具。
  • 第四,二进制的符号“1”和“0”恰好与逻辑运算中的“对”(true)与“错”(false)对应,便于计算机进行逻辑运算。

二进制运算

二进制加法有四种情况: 0+0=0,0+1=1,1+0=1,1+1=10(0 进位为1)

二进制乘法有四种情况: 0×0=0,1×0=0,0×1=0,1×1=1

二进制减法有四种情况:0-0=0,1-0=1,1-1=0,0-1=1

二进制除法有两种情况(除数只能为1):0÷1=0,1÷1=1

java中的位运算

Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。

位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:

        A = 0011 1100B = 0000 1101-----------------A & B = 0000 1100A | B = 0011 1101A ^ B = 0011 0001~A    = 1100 0011

下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:

操作符 描述 例子
如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
如果相对应位都是 0,则结果为 0,否则为 1 (A 丨B)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011
<< 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000
>> 按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111

测试栗子:

    public class BitOperation {public static void main(String[] args) {int a = 60; /* 60 = 0011 1100 */int b = 13; /* 13 = 0000 1101 */int c = 0;c = a & b;       /* 12 = 0000 1100 */System.out.println("a & b = " + c );c = a | b;       /* 61 = 0011 1101 */System.out.println("a | b = " + c );c = a ^ b;       /* 49 = 0011 0001 */System.out.println("a ^ b = " + c );c = ~a;          /*-61 = 1100 0011 */System.out.println("~a = " + c );c = a << 2;     /* 240 = 1111 0000 */System.out.println("a << 2 = " + c );c = a >> 2;     /* 15 = 1111 */System.out.println("a >> 2  = " + c );c = a >>> 2;     /* 15 = 0000 1111 */System.out.println("a >>> 2 = " + c );}}

输出:

    a & b = 12a | b = 61a ^ b = 49~a = -61a << 2 = 240a >> 2  = 15a >>> 2 = 15

ThreadPoolExecutor 源码分析

AtomicInteger ctl

ctl是主要的控制状态,是一个复合类型的变量,其中包括了两个概念。

  • workerCount:表示有效的线程数目
  • runState:线程池里线程的运行状态

我们来分析一下跟ctl有关的一些源代码吧,直接上代码

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));//用来表示线程池数量的位数,很明显是29,Integer.SIZE=32private static final int COUNT_BITS = Integer.SIZE - 3;//线程池最大数量,2^29 - 1private static final int CAPACITY   = (1 << COUNT_BITS) - 1;// runState is stored in the high-order bits//我们可以看出有5种runState状态,证明至少需要3位来表示runState状态//所以高三位就是表示runState了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;// Packing and unpacking ctlprivate 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; }

CAPACITY: 线程最大数量

在这里我们讲一下这个线程池最大数量的计算吧,因为这里涉及到源码以及位移之类的操作,我感觉大多数人都还是不太会这个,因为我一开始看的时候也是不太会的。

    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

从代码我们可以看出,是需要1往左移29位,然后再减去1,那个1往左移29位是怎么计算的呢?

    1 << COUNT_BITS1的32位2进制是0000 0000 0000 0000 0000 0000 0000 0001左移29位的话就是0010 0000 0000 0000 0000 0000 0000 0000再进行减一的操作0001 1111 1111 1111 1111 1111 1111 1111也就是说线程池最大数目就是0001 1111 1111 1111 1111 1111 1111 1111

runState:线程池里线程的运行状态

正数的原码、反码、补码都是一样的,在计算机底层,是用补码来表示的

    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;

RUNNING 运行状态

可以接受新任务并且处理已经在阻塞队列的任务,高3位全部是1的话,就是RUNNING状态

    -1 << COUNT_BITS这里是-1往左移29位,稍微有点不一样,-1的话需要我们自己算出补码来-1的原码1000 0000 0000 0000 0000 0000 0000 0001-1的反码,负数的反码是将原码除符号位以外全部取反1111 1111 1111 1111 1111 1111 1111 1110-1的补码,负数的补码就是将反码+11111 1111 1111 1111 1111 1111 1111 1111关键了,往左移29位,所以高3位全是1就是RUNNING状态1110 0000 0000 0000 0000 0000 0000 0000

SHUTDOWN 关闭状态

不接受新任务,处理已经在阻塞队列的任务,高3位全是0,就是SHUTDOWN状态

    0 << COUNT_BITS0的表示00000000 00000000 00000000 00000000往左移29位00000000 00000000 00000000 00000000

STOP

不接受新任务,也不处理阻塞队列里的任务,并且会中断正在处理的任务,所以高3位是001,就是STOP状态

    1 << COUNT_BITS1的表示00000000 00000000 00000000 00000001往左移29位00100000 00000000 00000000 00000000

TIDYING

所有任务都被中止,workerCount是0,线程状态转化为TIDYING并且调用terminated()钩子方法,所以高3位是010,就是TIDYING状态

    2 << COUNT_BITS2的32位2进制00000000 00000000 00000000 00000010往左移29位01000000 00000000 00000000 00000000

TERMINATED

terminated()钩子方法已经完成,所以高3位是110,就是TERMINATED状态

    3 << COUNT_BITS3的32位2进制00000000 00000000 00000000 00000011往左移29位11000000 00000000 00000000 00000000

相关方法介绍

runStateOf

实时获取runState的方法

    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    ~CAPACITY~是按位取反的意思&是按位与的意思而CAPACITY是,高位3个0,低29位都是1,所以是000 11111 11111111 11111111 11111111取反的话就是111 00000 00000000 00000000 00000000传进来的c参数与取反的CAPACITY进行按位与操作1、低位29个0进行按位与,还是29个02、高位3个1,即保持c参数的高3位即高位保持原样,低29位都是0,这也就获得了线程池的运行状态runState

workerCountOf

获取线程池的当前有效线程数目

    private static int workerCountOf(int c)  { return c & CAPACITY; }
    CAPACITY的32位2进制是000 11111 11111111 11111111 11111111用入参c跟CAPACITY进行按位与操作1、低29位都是1,所以保留参数c的低29位,也就是有效线程数2、高3位都是0,所以c的高3位也是0这样获取出来的便是workerCount的值

ctlOf

原子整型变量ctl的初始化方法

//结合这几句代码来看private static final int RUNNING    = -1 << COUNT_BITS;private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));private static int ctlOf(int rs, int wc) { return rs | wc; }
    RUNNING是1110 0000 0000 0000 0000 0000 0000 0000ctlOf是将rs和wc进行按位或的操作初始化的时候是将RUNNING和0进行按位或0的32位2进制是0000 0000 0000 0000 0000 0000 0000 0000所以初始化的ctl是1110 0000 0000 0000 0000 0000 0000 0000

【多线程】ThreadPoolExecutor类源码解析----续(二进制相关运算)相关推荐

  1. java.lang 源码剖析_java.lang.Void类源码解析

    在一次源码查看ThreadGroup的时候,看到一段代码,为以下: /* * @throws NullPointerException if the parent argument is {@code ...

  2. Node 学习六、核心模块 events之 01 events 和 EventEmitter 类、发布订阅、EventEmitter 类源码解析和模拟实现

    events 事件模块 events 与 EventEmitter node.js 是基于事件驱动的异步操作架构,内置 events 模块 events 模块提供了 EventEmitter 类 这个 ...

  3. Scroller类源码解析及其应用(一)

    滑动是我们在自定义控件时候经常遇见的难题,让新手们倍感困惑,这篇文章主要介绍Scroller类的源码,告诉打击这个到底有什么用,怎么使用它来控制滑动.另外,我还会结合一个简单的例子,来看一下这个类的应 ...

  4. Java FileReader InputStreamReader类源码解析

    FileReader 前面介绍FileInputStream的时候提到过,它是从文件读取字节,如果要从文件读取字符的话可以使用FileReader.FileReader是可以便利读取字符文件的类,构造 ...

  5. Java String类源码解析

    String直接继承Object 含有一个char[] value,还有一个int hash默认值为0 new String()的构造产生的是一个值为""的字符数组 String( ...

  6. Java集合---Arrays类源码解析

    一.Arrays.sort()数组排序 Java Arrays中提供了对所有类型的排序.其中主要分为Primitive(8种基本类型)和Object两大类. 基本类型:采用调优的快速排序: 对象类型: ...

  7. Unsafe类源码解析

    前言 Unsafe,顾名思义,一个不安全的类,那么jdk的开发者为什么要设计一个不安全的类呢?这个类为什么会不安全呢?现在就让我们来揭开Unsafe类的神秘面纱. 1.概述 作为java开发者的我们都 ...

  8. Java多线程——Thread Runnable源码解析

    Java多线程的两种实现方法大家都应该知道了:继承Thread的子类实例化和实现Runnable接口用这个接口实现类去创建Thread实例. Java的线程在Linux平台上使用的是NPTL机制,JV ...

  9. Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析

    对类的植入锁定进行判断 几个可以对覆盖率跟踪的Java类定义进行instrument的API public byte[] instrument(final ClassReader reader) {f ...

最新文章

  1. docker-compose的安装与简单使用
  2. 大神程序员,夜夜coding到天明?Python之父昼伏夜出,PHP创始人24小时都在线
  3. C++ int与string的转化
  4. 关于application title一直是untitled的问题
  5. 如何在vs中创建r树索引代码_线段树详解与实现
  6. 极大似然估计和贝叶斯估计
  7. 野生前端的数据结构基础练习(6)——集合
  8. 每日算法系列【LeetCode 992】K个不同整数的子数组
  9. html引用ttf字体文件
  10. 怎样给div增加resize事件
  11. python写sql语句_Python 数据分析:让你像写 Sql 语句一样,使用 Pandas 做数据分析...
  12. 背诵华为hcia认证考试题库答案能过吗?华为认证等级是怎样的
  13. matlab线性代数对角化,工程线性代数(MATLAB版) (2007年7月)
  14. Android入门,android基础开发
  15. JMS 消息传送模式、消息签收以及spring jmsTemplate配置
  16. Arrayfire E0992 命令行错误: 宏定义无效: AF_<CPU/CUDA/OPENCL>
  17. 非淡泊无以明志,非宁静无以致远
  18. 【IoT】BLE 广播的基础数据定义:广播名字类型和设备类型标志
  19. python中图片绘制和输出相关库的原理详解
  20. 《web开发: Ajax 介绍》

热门文章

  1. 2009年9月三级网络技术51CTO版考前压轴试题
  2. 计算机与计算科学是属什么专业,被录取到信息与计算科学专业,这个专业什么性质,发展前景如何?...
  3. 磁头号和起始扇区的计算方法------软盘结构
  4. Yacc 与 Lex 快速入门(词法分析和语法分析)
  5. 已解决:Job for docker.service failed because the control process exited with error code. See “systemctl
  6. lua源代码分析01:lua源代码结构分析
  7. 简述DNS进行域名正向解析的过程。
  8. 4.STM32中对USART1_Config()函数的理解(自定义)
  9. spring12:@Component衍生注解
  10. mybaits三:全局配置文件(全面)