當前位置:
首頁 > 知識 > 線程池ThreadPoolExecutor里Control state,ctl參數的分析(一)

線程池ThreadPoolExecutor里Control state,ctl參數的分析(一)

線程池ThreadPoolExecutor里Control state,ctl參數的分析(一)

線程池

打開ThreadPoolExecutor的源代碼,第一個變數就是:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

這是一個原子INT操作類,這個值非常有意思,表面上看,這是一個int值,按照一般的理解,代表一個數字,一種狀態,比如,0女1男,1開始2運行中3結束等等。

但是在ThreadPoolExecutor中,這一個數字卻代表了兩個概念:

1、 workerCount,有效的線程數。

2、 runState,線程池運行的狀態(具體文後再談)。

一般人看到這會有疑問(好吧,這其實是我的疑問,也是本篇文章的寫作初衷):

  1. 為什麼要用一個數字表達兩個概念?
  2. 如何用一個數字來表達兩個概念?

先說第一個問題。一般開發人員(比如我這樣的)遇到這種情況估計直接:

private int workerCount = 0;
private int runState = 0;

如果考慮線程安全的話,大不了用AtomicInteger就是。

但是大家要考慮到ThreadPoolExecutor是java.util.concurrent包中的線程池,是基礎類,也是對性能要求很高的並發包,在性能上儘可能做到極致,是大神們自然而然的選擇。所以能用一個數字解決的問題,就不再用兩個。一個int32位(4位元組),現在的內存白菜價,以前的內存可貴了~~

重點是第二個問題,很多人不明白一個數字是怎麼能表達兩個概念的(其實是我不明白)。

在一般程序員眼中,一個數字就是一個數字,但是在大神們的眼中,一個int數字則是一個32位的二進位啊!32個0、1的組合,可以搞出很多事情來。

來補補基礎課~~

比如數字15,32位二進位的表達就是:00000000000000000000000000001111。

二進位使用最高位作為符號位, 0正數, 1負數。

所以int的最大值的二進位就是01111111111111111111111111111111=2147483647

最小值10000000000000000000000000000000=-2147483648

我們可以輕易得出1=00000000000000000000000000000001

-1= 10000000000000000000000000000001

但其實計算機里不是這麼做的,這涉及二進位的原碼、反碼、補碼的表達方式,簡單地說:

-1的原碼:10000000000000000000000000000001

-1的反碼:符號位不變,其他位取反

-1的補碼:反碼+1

所以應該是:

原碼:10000000000000000000000000000001

反碼:11111111111111111111111111111110

補碼:11111111111111111111111111111111

計算機使用的是補碼。

線程池的運行狀態runState,狀態值只有固定的5個:-1,0,1,2,3(具體含義文後再談),其二進位表達為:

-1:11111111111111111111111111111111

0:00000000000000000000000000000000

1:00000000000000000000000000000001

2:00000000000000000000000000000010

3:00000000000000000000000000000011

但是大家注意,因為狀態值是固定的,所以用32位來表達其實是浪費了,實際只要3位就可以表達5個數字,即1個符號位,2個數值位

可以簡化為:

-1:111

0:000

1:001

2:010

3:011

所以大神們就決定ctl這個int值的32位二進位值中,前3個用來表示狀態值runState。

後面的32-3=29位,就用來表示workerCount線程數。

所以我們就得出了ThreadPoolExecutor類中第二個變數:

private static final int COUNT_BITS = Integer.SIZE - 3;

那麼也可以得出,線程數的最大值就是29個1:00011111111111111111111111111111= 536870911=2^29-1。

所以我們就得出了ThreadPoolExecutor類中第三個變數,線程池最大容量:

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

至於如何構建ctl,如何從ctl獲取需要的runState、workerCount,下篇文章再分析。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Java個人學習心得 的精彩文章:

個人關於數據結構與演算法的一點學習筆記(一)
總結對==、equals、hashCode的認識

TAG:Java個人學習心得 |