1. 詳解Java線程池的ctl(線程池控制狀態(tài))【源碼分析】

        共 717字,需瀏覽 2分鐘

         ·

        2020-08-16 08:34

        點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

        優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

        ? 作者?|?moonfair?

        來(lái)源 | urlify.cn/JFfe6j

        66套java從入門到精通實(shí)戰(zhàn)課程分享

        0.綜述

        1. ?ctl?是線程池源碼中常常用到的一個(gè)變量。

        2. 它的主要作用是記錄線程池的生命周期狀態(tài)和當(dāng)前工作的線程數(shù)。

        3. 作者通過(guò)巧妙的設(shè)計(jì),將一個(gè)整型變量按二進(jìn)制位分成兩部分,分別表示兩個(gè)信息。

        1.聲明與初始化

          源碼:

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


          分析一波:

        1. ?ctl?(線程池控制狀態(tài))是原子整型的,這意味這對(duì)它進(jìn)行的操作具有原子性。

        2. 如此一來(lái),作為?ctl?組成部分的?runState?(線程池生命周期狀態(tài))和?workerCount?(工作線程數(shù)) 也將同時(shí)具有原子性。

        3. ?ThreadPoolExecutor?使用 ?ctlOf?方法來(lái)將 ?runState?和 ?workerCount?兩個(gè)變量(都是整型)打包成一個(gè)?ctl? 變量。稍后將解讀這個(gè)方法的實(shí)現(xiàn)。

        2.兩個(gè)工具人常量 COUNT_BITS 和 CAPACITY?

          源碼:

        1?private?static?final?int?COUNT_BITS = Integer.SIZE - 3;
        2?private?static?final?int?CAPACITY = (1?<< COUNT_BITS) - 1;


          分析一波:

        1. COUNT_BITS? 常量的值為?Integer.SIZE - 3?,其中?Integer.SIZE?為整型最大位數(shù),在本文剩余部分,我們?nèi)∑錇?32?。

        2. 如此?COUNT_BITS?實(shí)際的值其實(shí)就是?29?。這里有些讀者可能會(huì)有 “為什么減去的數(shù)是 3 而不是別的” 的疑惑,這將在后文得到解答。

        3. CAPACITY? 常量的值為 ?(1 << COUNT_BITS) - 1?,其中?<<?為左移運(yùn)算符,這么說(shuō)可能不太直觀,我以二進(jìn)制直接寫(xiě)出這個(gè)數(shù)將有助于理解:

          1
          0000 0000 0000 0001
          1 << 29 - 1
          0001 1111 1111 1111
        4. 因此在接下來(lái)的代碼中,?COUNT_BITS?就用來(lái)表示分隔runState?和workerCount?的位數(shù);

        5. CAPACITY?則作為取這兩個(gè)變量(?runState?和?workerCount?)的工具(具體是怎么使用的請(qǐng)看下文)

        3.線程池生命周期狀態(tài)常量

        ?  源碼:

        1?private?static?final?int?RUNNING = -1?<< COUNT_BITS;
        2?private?static?final?int?SHUTDOWN = 0?<< COUNT_BITS;
        3?private?static?final?int?STOP = 1?<< COUNT_BITS;
        4?private?static?final?int?TIDYING = 2?<< COUNT_BITS;
        5?private?static?final?int?TERMINATED = 3?<< COUNT_BITS;


          分析一波:

        1. 這里解答了上邊關(guān)于?COUNT_BITS?變量為什么要減 3 的問(wèn)題:因?yàn)榫€程池的生命周期有 5 個(gè)狀態(tài),為了表達(dá)這 5 個(gè)狀態(tài),我們需要 3 個(gè)二進(jìn)制位。

        2. 對(duì)線程池的生命周期有興趣的讀者請(qǐng)百度?線程池生命周期?;不明白為什么 5 個(gè)狀態(tài)需要 3 個(gè)二進(jìn)制位的請(qǐng)百度?二進(jìn)制?。

        3. 注意到這里標(biāo)注狀態(tài)使用的并不是?-1 ~ 3?,而是這 5 個(gè)數(shù)字分別左移?COUNT_BITS?位,這樣做的好處將在接下來(lái)的代碼中得到體現(xiàn)。

        4.打包函數(shù)與拆包函數(shù)

          源碼:

        1?//拆包函數(shù)
        2?private?static?int?runStateOf(int?c)?????{ return?c & ~CAPACITY; }
        3?private?static?int?workerCountOf(int?c)??{ return?c & CAPACITY; }
        4?//打包函數(shù)
        5?private?static?int?ctlOf(int?rs, int?wc)?{ return?rs | wc; }


          分析一波:

        1. 此處我們解答了?CAPACITY?常量的作用,之前提到過(guò),他是一個(gè)后 29 位均為 1 ,前 3 位為 0 的整數(shù),因此我們可以通過(guò):

        2. 對(duì)?CAPACITY?和?ctl?進(jìn)行?&?(按位與)操作就能取到?ctl?的后 29 位,即??workerCount?。

        3. 對(duì)?CAPACITY?進(jìn)行?~?(按位取反)操作后,再和?ctl?進(jìn)行?&?操作就能取到?runState?。它的高 3 位是?ctl?的高 3 位,低 29 位為 0。這也解釋了為什么之前提到的生命周期常量要在?-1 ~ 3?的基礎(chǔ)上再左移 29 位,因?yàn)椴辉诔A砍跏蓟幾笠频脑捑鸵诓鸢臅r(shí)候右移來(lái)保證取到的是正確的數(shù)值。然而拆包操作是要經(jīng)常進(jìn)行的,而常量的初始化只有一次。兩下對(duì)比,明顯在初始化時(shí)左移是效率更高的選擇。

        4. 除了拆包時(shí)的效率,常量初始化時(shí)左移也提高了打包函數(shù)的效率:此處打包函數(shù)可以直接對(duì)?runState?和?workerCount?進(jìn)行?|?(按位或)操作來(lái)得到?ctl?變量,就是因?yàn)?runState?的高 3 位為有效信息,而?workerCount?的低 29 位為有效信息,合起來(lái)正好得到一個(gè)含 32 位有效信息的整型變量。

        5. 說(shuō)到這里可能仍有些讓人疑惑,我將再以二進(jìn)制的形式表示出所有涉及到的變量/常量:


        6. //下文中a和b分別代表runState和workerCount的有效信息

          //CAPACITY
          0001 1111 1111 1111
          //ctl
          aaab bbbb bbbb bbbb
          //runState
          aaa0 0000 0000 0000
          //workerCount
          000b bbbb bbbb bbbb

        5.運(yùn)行狀態(tài)的判斷

          源碼:

        private?static?boolean?runStateLessThan(int?c, int?s)?{
        ????????return?c < s;
        ????}

        ????private?static?boolean?runStateAtLeast(int?c, int?s)?{
        ????????return?c >= s;
        ????}

        ????private?static?boolean?isRunning(int?c)?{
        ????????return?c < SHUTDOWN;
        ????}

          分析一波:

        1. 注意這里傳入的s是用了之前定義的生命周期常量。

        2. 這里判斷狀態(tài)的大小時(shí),直接將c?和s?進(jìn)行了比較,這是因?yàn)榇頎顟B(tài)的信息占據(jù)了兩個(gè)變量的高 3 位,而比較高位的大小時(shí),低位是沒(méi)有影響的。

        6.修改ctl中workCount的大小

          源碼:

        private?boolean?compareAndIncrementWorkerCount(int?expect)?{
        ????????return?ctl.compareAndSet(expect, expect + 1);
        ????}

        ????private?boolean?compareAndDecrementWorkerCount(int?expect)?{
        ????????return?ctl.compareAndSet(expect, expect - 1);
        ????}

        ????private?void?decrementWorkerCount()?{
        ????????do?{} while?(! compareAndDecrementWorkerCount(ctl.get()));
        ????}

          分析一波:

        1. 注意到這里的修改都使用了原子整型的CAS方法。

        7.修改ctl中runState的大小

          源碼:

        1?ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))

          分析一波:

        1. 注意到修改?runState?并沒(méi)有再提供專門的方法,而是直接使用了原子整型的CAS方法來(lái)替換原來(lái)的?ctl?。

        ?8.仍存在的疑問(wèn)

        • Q1:如果經(jīng)過(guò)遞增?compareAndIncrementWorkerCount?,使得?workerCount?的大小超過(guò)29位,會(huì)發(fā)生什么?會(huì)有安全檢查嗎?

        • Q2:為什么為?workerCount?的修改提供了方法,卻沒(méi)有為?runState?的修改提供?



        粉絲福利:108本java從入門到大神精選電子書(shū)領(lǐng)取

        ???

        ?長(zhǎng)按上方二維碼?2 秒
        回復(fù)「1234」即可獲取資料以及
        可以進(jìn)入java1234官方微信群



        感謝點(diǎn)贊支持下哈?

        瀏覽 53
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 女女互摸吃奶互慰视频免费app | 91AV三级影院 | 美女扒开粉嫩的尿口 | 91成人 在线观看喷潮 | 男女插插视频 |