【多线程】ThreadPoolExecutor类源码解析----续(二进制相关运算)
前言
在之前閱讀 ThreadPoolExecutor 源碼的時候,發(fā)現(xiàn)代碼里用到了一些二進(jìn)制相關(guān)的位運算之類的代碼,看起來有些費勁了,所以現(xiàn)在大概總結(jié)了一些筆記,二進(jìn)制這東西吧,不難,就跟數(shù)學(xué)一樣,知道規(guī)律,計算公式,就賊簡單,就是二進(jìn)制轉(zhuǎn)十進(jìn)制這種自己算起來比較費勁
但現(xiàn)在又不是考試,所以我選擇計算器!!!!
二進(jìn)制
計算機采用二進(jìn)制原因:
- 首先,二進(jìn)位計數(shù)制僅用兩個數(shù)碼。0和1,所以,任何具有二個不同穩(wěn)定狀態(tài)的元件都可用來表示數(shù)的某一位。而在實際上具有兩種明顯穩(wěn)定狀態(tài)的元件很多。例如,氖燈的亮和熄;開關(guān)的開和關(guān); 電壓的高和低、正和負(fù);紙帶上的有孔和無孔,電路中的有信號和無信號, 磁性材料的南極和北極等等,不勝枚舉。 利用這些截然不同的狀態(tài)來代表數(shù)字,是很容易實現(xiàn)的。不僅如此,更重要的是兩種截然不同的狀態(tài)不單有量上的差別,而且是有質(zhì)上的不同。這樣就能大大提高機器的抗干擾能力,提高可靠性。而要找出一個能表示多于二種狀態(tài)而且簡單可靠的器件,就困難得多了。
- 其次,二進(jìn)位計數(shù)制的四則運算規(guī)則十分簡單。而且四則運算最后都可歸結(jié)為加法運算和移位,這樣,電子計算機中的運算器線路也變得十分簡單了。不僅如此,線路簡化了,速度也就可以提高。這也是十進(jìn)位計數(shù)制所不能相比的 。
- 第三,在電子計算機中采用二進(jìn)制表示數(shù)可以節(jié)省設(shè)備。可 以從理論上證明,用三進(jìn)位制最省設(shè)備,其次就是二進(jìn)位制。但由于二進(jìn)位制有包括三進(jìn)位制在內(nèi)的其他進(jìn)位制所沒有的優(yōu)點,所以大多數(shù)電子計算機還是采用二進(jìn)制。此外,由于二進(jìn)制中只用二個符號 “ 0” 和“1”,因而可用布爾代數(shù)來分析和綜合機器中的邏輯線路。 這為設(shè)計電子計算機線路提供了一個很有用的工具。
- 第四,二進(jìn)制的符號“1”和“0”恰好與邏輯運算中的“對”(true)與“錯”(false)對應(yīng),便于計算機進(jìn)行邏輯運算。
二進(jìn)制運算
二進(jìn)制加法有四種情況: 0+0=0,0+1=1,1+0=1,1+1=10(0 進(jìn)位為1)
二進(jìn)制乘法有四種情況: 0×0=0,1×0=0,0×1=0,1×1=1
二進(jìn)制減法有四種情況:0-0=0,1-0=1,1-1=0,0-1=1
二進(jìn)制除法有兩種情況(除數(shù)只能為1):0÷1=0,1÷1=1
java中的位運算
Java定義了位運算符,應(yīng)用于整數(shù)類型(int),長整型(long),短整型(short),字符型(char),和字節(jié)型(byte)等類型。
位運算符作用在所有的位上,并且按位運算。假設(shè)a = 60,b = 13;它們的二進(jìn)制格式表示將如下:
A = 0011 1100B = 0000 1101-----------------A & B = 0000 1100A | B = 0011 1101A ^ B = 0011 0001~A = 1100 0011下表列出了位運算符的基本運算,假設(shè)整數(shù)變量 A 的值為 60 和變量 B 的值為 13:
| & | 如果相對應(yīng)位都是1,則結(jié)果為1,否則為0 | (A&B),得到12,即0000 1100 |
| 丨 | 如果相對應(yīng)位都是 0,則結(jié)果為 0,否則為 1 | (A 丨B)得到61,即 0011 1101 |
| ^ | 如果相對應(yīng)位值相同,則結(jié)果為0,否則為1 | (A ^ B)得到49,即 0011 0001 |
| ? | 按位取反運算符翻轉(zhuǎn)操作數(shù)的每一位,即0變成1,1變成0。 | (?A)得到-61,即1100 0011 |
| << | 按位左移運算符。左操作數(shù)按位左移右操作數(shù)指定的位數(shù)。 | A << 2得到240,即 1111 0000 |
| >> | 按位右移運算符。左操作數(shù)按位右移右操作數(shù)指定的位數(shù)。 | A >> 2得到15即 1111 |
| >>> | 按位右移補零操作符。左操作數(shù)的值按右操作數(shù)指定的位數(shù)右移,移動得到的空位以零填充。 | A>>>2得到15即0000 1111 |
測試?yán)踝?#xff1a;
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 = 15ThreadPoolExecutor 源碼分析
AtomicInteger ctl
ctl是主要的控制狀態(tài),是一個復(fù)合類型的變量,其中包括了兩個概念。
- workerCount:表示有效的線程數(shù)目
- runState:線程池里線程的運行狀態(tài)
我們來分析一下跟ctl有關(guān)的一些源代碼吧,直接上代碼
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));//用來表示線程池數(shù)量的位數(shù),很明顯是29,Integer.SIZE=32private static final int COUNT_BITS = Integer.SIZE - 3;//線程池最大數(shù)量,2^29 - 1private static final int CAPACITY = (1 << COUNT_BITS) - 1;// runState is stored in the high-order bits//我們可以看出有5種runState狀態(tài),證明至少需要3位來表示runState狀態(tài)//所以高三位就是表示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: 線程最大數(shù)量
在這里我們講一下這個線程池最大數(shù)量的計算吧,因為這里涉及到源碼以及位移之類的操作,我感覺大多數(shù)人都還是不太會這個,因為我一開始看的時候也是不太會的。
private static final int CAPACITY = (1 << COUNT_BITS) - 1;從代碼我們可以看出,是需要1往左移29位,然后再減去1,那個1往左移29位是怎么計算的呢?
1 << COUNT_BITS1的32位2進(jìn)制是0000 0000 0000 0000 0000 0000 0000 0001左移29位的話就是0010 0000 0000 0000 0000 0000 0000 0000再進(jìn)行減一的操作0001 1111 1111 1111 1111 1111 1111 1111也就是說線程池最大數(shù)目就是0001 1111 1111 1111 1111 1111 1111 1111runState:線程池里線程的運行狀態(tài)
正數(shù)的原碼、反碼、補碼都是一樣的,在計算機底層,是用補碼來表示的
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 運行狀態(tài)
可以接受新任務(wù)并且處理已經(jīng)在阻塞隊列的任務(wù),高3位全部是1的話,就是RUNNING狀態(tài)
-1 << COUNT_BITS這里是-1往左移29位,稍微有點不一樣,-1的話需要我們自己算出補碼來-1的原碼1000 0000 0000 0000 0000 0000 0000 0001-1的反碼,負(fù)數(shù)的反碼是將原碼除符號位以外全部取反1111 1111 1111 1111 1111 1111 1111 1110-1的補碼,負(fù)數(shù)的補碼就是將反碼+11111 1111 1111 1111 1111 1111 1111 1111關(guān)鍵了,往左移29位,所以高3位全是1就是RUNNING狀態(tài)1110 0000 0000 0000 0000 0000 0000 0000SHUTDOWN 關(guān)閉狀態(tài)
不接受新任務(wù),處理已經(jīng)在阻塞隊列的任務(wù),高3位全是0,就是SHUTDOWN狀態(tài)
0 << COUNT_BITS0的表示00000000 00000000 00000000 00000000往左移29位00000000 00000000 00000000 00000000STOP
不接受新任務(wù),也不處理阻塞隊列里的任務(wù),并且會中斷正在處理的任務(wù),所以高3位是001,就是STOP狀態(tài)
1 << COUNT_BITS1的表示00000000 00000000 00000000 00000001往左移29位00100000 00000000 00000000 00000000TIDYING
所有任務(wù)都被中止,workerCount是0,線程狀態(tài)轉(zhuǎn)化為TIDYING并且調(diào)用terminated()鉤子方法,所以高3位是010,就是TIDYING狀態(tài)
2 << COUNT_BITS2的32位2進(jìn)制00000000 00000000 00000000 00000010往左移29位01000000 00000000 00000000 00000000TERMINATED
terminated()鉤子方法已經(jīng)完成,所以高3位是110,就是TERMINATED狀態(tài)
3 << COUNT_BITS3的32位2進(jìn)制00000000 00000000 00000000 00000011往左移29位11000000 00000000 00000000 00000000相關(guān)方法介紹
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傳進(jìn)來的c參數(shù)與取反的CAPACITY進(jìn)行按位與操作1、低位29個0進(jìn)行按位與,還是29個02、高位3個1,即保持c參數(shù)的高3位即高位保持原樣,低29位都是0,這也就獲得了線程池的運行狀態(tài)runStateworkerCountOf
獲取線程池的當(dāng)前有效線程數(shù)目
private static int workerCountOf(int c) { return c & CAPACITY; } CAPACITY的32位2進(jìn)制是000 11111 11111111 11111111 11111111用入?yún)跟CAPACITY進(jìn)行按位與操作1、低29位都是1,所以保留參數(shù)c的低29位,也就是有效線程數(shù)2、高3位都是0,所以c的高3位也是0這樣獲取出來的便是workerCount的值ctlOf
原子整型變量ctl的初始化方法
//結(jié)合這幾句代碼來看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進(jìn)行按位或的操作初始化的時候是將RUNNING和0進(jìn)行按位或0的32位2進(jìn)制是0000 0000 0000 0000 0000 0000 0000 0000所以初始化的ctl是1110 0000 0000 0000 0000 0000 0000 0000總結(jié)
以上是生活随笔為你收集整理的【多线程】ThreadPoolExecutor类源码解析----续(二进制相关运算)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【多线程】ThreadPoolExecu
- 下一篇: 【多线程】线程池拒绝策略详解与自定义拒绝