您好,登錄后才能下訂單哦!
本篇內容介紹了“如何從線程池狀態管理來看二進制操作”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
首先,為了文章的完整性,我們還是先了解一下線程池的狀態,總結如下如:
線程池狀態分為5種:RUNNING
、SHUTDOWN
、STOP
、TIDYING
、TERMINATED
RUNNING:(運行)接收新task,并且處理正在排隊的task,不中斷正在執行的任務
SHUTDOWN:(關閉)不接受新的task,只處理正在排隊的task,不中斷正在執行的任務
STOP:(停止)不接受新的task,也不處理正在排隊的task,并且中斷正在執行的任務
TIDYING:(整理)所有的task都已經終止,上述提到的workCount當前活躍線程數為0,被中斷的任務和正在排隊的任務執行當前任務的terminated()鉤子方法
TERMINATED:(已終止)標識上述的TIDYING的過程結束,標識當前線程池成功完全停止的狀態
大致的流程就是:
RUNNING
--> SHUTDOWN
--> STOP
--> TIDYING
--> TERMINATED
上述流程是一個單方向的順序,也就是說不會出現類似于STOP
--> SHUTDOWN
這種情況;
另外,并不是每一個狀態多必須經過的;
什么時候進行線程池的狀態轉換呢?
RUNNING -> SHUTDOWN:調用終止線程的方法shutdown()
后
RUNNING or SHUTDOWN -> STOP:調用shutdownNow()
方法后,不管當前在RUNNING狀態還是SHUTDOWN狀態,都是直接轉為STOP狀態
SHUTDOWN -> TIDYING:SHUTDOWN狀態下當等待隊列 和 正在執行的任務 都為空時,狀態轉為TIDYING
STOP -> TIDYING:STOP狀態下當正在執行的任務全部中斷完畢后,狀態轉為TIDYING
TIDYING -> TERMINATED:TIDYING狀態下當所有的terminated()鉤子方法全部執行完畢后,狀態轉為TERMINATED,線程池關閉完畢!
線程池中管理線程池狀態 和 線程池當前活躍線程數,是通過一個AtomicInteger變量來管理這兩個狀態的
什么? 一個變量管理兩個這么不相干的狀態? 對的;
讓我們來看一下線程池針對這部分的實現:
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; // runState is stored in the high-order bits 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 ctl 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; } private static boolean isRunning(int c) { return c < SHUTDOWN;}
下面,我們來剖析一下上述的實現: 線程池包含5種狀態如下:具體線程的狀態代表的含義和狀態的轉換,下面會有講解:
private static final int COUNT_BITS = Integer.SIZE - 3; 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;
我們知道在java中 int 類型占用4個字節32位存儲, 上述的幾種狀態: 底層存儲二進制為:
1111 1111 1111 1111 1111 1111 1111 1111(-1) 0000 0000 0000 0000 0000 0000 0000 0000(0) 0000 0000 0000 0000 0000 0000 0000 0001(1) 0000 0000 0000 0000 0000 0000 0000 0010(2) 0000 0000 0000 0000 0000 0000 0000 0011(3)
左移<<COUNT_BITS位
,COUNT_BITS = Integer.SIZE - 3
也就是 COUNT_BITS = 29
,改句子說明用32位的前3位存儲線程池的狀態 后29位存儲線程池中當前線程的個數, << COUNT_BITS
后,變為下面的二進制:
1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 0000 0000 0000 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000 0110 0000 0000 0000 0000 0000 0000 0000
我們可以看到,前三位存儲的是 標識線程狀態的二進制
對于初始化存儲這些狀態的變量AtomicInteger ctl
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0))
初始化AtomicInteger變量ctl
,其中ctlOf(RUNNING, 0)
代碼為:
private static int ctlOf(int rs, int wc) { return rs | wc; }
其中rs標識線程池當前狀態,wc為work count標識當前工作線程的數量
上述傳入的是ctlOf(RUNNING, 0)
,當前狀態為RUNING也就是1110 0000 0000 0000 0000 0000 0000 0000
,wc為0,也就是當前工作線程數為0,其二進制為0000 0000 0000 0000 0000 0000 0000 0000
,做"|"
或操作,即
1110 0000 0000 0000 0000 0000 0000 0000 | 0000 0000 0000 0000 0000 0000 0000 0000 = 1110 0000 0000 0000 0000 0000 0000 0000
上述得到的結果1110 0000 0000 0000 0000 0000 0000 0000
就標識,當前線程池狀態為RUNNING,線程池活躍線程個數為0!
通過上述創建的ctl變量獲取 線程池當前狀態 和 線程中活躍線程個數 這兩個狀態:
獲取線程池當前狀態,我們可以想一下該如何獲取呢? 現在知道的是ctl的前3位是線程池的狀態,那我們直接構造一個前三位為1,后29位為0的int即可,然后取余就可以了唄,下面看下源碼的實現,就是如此: 使用方法runStateOf
private static int runStateOf(int c) { return c & ~CAPACITY; }
其中CAPACITY = (1 << COUNT_BITS) - 1
轉化為二進制為: 0001 1111 1111 1111 1111 1111 1111 1111
取反"~"后,二進制為: 1110 0000 0000 0000 0000 0000 0000 0000
也就是將前3位全部變為1,后面全部變為0; 接下來,傳入的ctl變量和~CAPACITY
做“&”操作,只會保留ctl變量的前3位變量,后29位變量全部為0;
例如:一個標識當前狀態為STOP狀態的線程池和當前活躍線程數為3的ctl變量為: 0010 0000 0000 0000 0000 0000 0000 0011
和上述得到的1110 0000 0000 0000 0000 0000 0000 0000
做“&”操作后得到: 0010 0000 0000 0000 0000 0000 0000 0000
和上述分析的STOP的狀態的二進制相同! 即獲得了當前線程的狀態!
獲取線程池當前狀態,也很簡單,我們知道ctl變量的32的后29位存儲的是當前活躍線程數,直接構造一個前三位為0,后29位為1的int即可,然后取余就可以獲取到了 使用方法workerCountOf
private static int workerCountOf(int c) { return c & CAPACITY; }
上述知道CAPACITY為:0001 1111 1111 1111 1111 1111 1111 1111
例如:一個標識當前狀態為STOP狀態的線程池和當前活躍線程數為3的ctl變量為: 0010 0000 0000 0000 0000 0000 0000 0011
和 0001 1111 1111 1111 1111 1111 1111 1111
取與后: 0000 0000 0000 0000 0000 0000 0000 0011
標識當前線程池中活躍線程數量為3!
1、計算ctl的值
方法:
private static int ctlOf(int rs, int wc) { return rs | wc; }
其中,入參rs代表當前線程狀態,wc代表當前活躍線程數,取“|”或即可 上述代碼不出現問題的前提是:rs只使用的前3位,wc只使用了后29位!
2、判斷當前線程池是否正在運行
方法:
private static boolean isRunning(int c) { return c <小于SHUTDOWN;}值即可!
上述我們知道,5中狀態只有RUNNING小于0,SHUTDOWN狀態等于0,其他的都是大于0的,所以我們直接把給定的ctl值小于SHUTDOWN值即可!
“如何從線程池狀態管理來看二進制操作”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。