線程池源碼問題的個人理解補(bǔ)充

今天看了部分線程池的代碼,對于線程池運(yùn)行機(jī)制又有了一些新的認(rèn)識, 本文是結(jié)合占小狼簡書 加了一些自己的理解和注釋.

該文只是作為個人對于占小狼關(guān)于深入分析java線程池的實(shí)現(xiàn)原理文的自己一些補(bǔ)充薪铜,建議先看他的文章之后再來看該文前方。有理解不對的地方望提出來共同學(xué)習(xí)蒂萎。

1.線程池內(nèi)部狀態(tài):
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; }

AtomicInteger變量ctl的功能非常強(qiáng)大:利用低29位表示線程池中線程數(shù)屯碴,通過高3位表示線程池的運(yùn)行狀態(tài):
1疤祭、RUNNING:-1 << COUNT_BITS票髓,即高3位為111森瘪,該狀態(tài)的線程池會接收新任務(wù)劝萤,并處理阻塞隊(duì)列中的任務(wù)闯狱;
2煞赢、SHUTDOWN: 0 << COUNT_BITS,即高3位為000哄孤,該狀態(tài)的線程池不會接收新任務(wù)照筑,但會處理阻塞隊(duì)列中的任務(wù);
3瘦陈、STOP : 1 << COUNT_BITS凝危,即高3位為001,該狀態(tài)的線程不會接收新任務(wù)晨逝,也不會處理阻塞隊(duì)列中的任務(wù)蛾默,而且會中斷正在運(yùn)行的任務(wù);
4咏花、TIDYING : 2 << COUNT_BITS趴生,即高3位為010阀趴;
5、TERMINATED: 3 << COUNT_BITS苍匆,即高3位為011刘急;

2.任務(wù)執(zhí)行
//得到c從而拿到內(nèi)部狀態(tài)
 int c = ctl.get();
        //拿到線程池中的線程數(shù),如果線程數(shù)小于核心線程數(shù)浸踩,那么直接創(chuàng)建新的線程執(zhí)行任務(wù)
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
           //會發(fā)現(xiàn)線程池中很多地方都會重復(fù)的得到內(nèi)部狀態(tài)叔汁,因?yàn)榫€程池主要是用CAS來保證的線程安全性,從而導(dǎo)致如果swap失敗的一些情況需要再次獲得最新的內(nèi)部狀態(tài)用之后做判斷检碗。
           //這里如果加入創(chuàng)建新的線程執(zhí)行任務(wù)的時候出現(xiàn)錯誤据块,重新獲取最新的內(nèi)部狀態(tài)用于之后使用
            c = ctl.get();
        }
        //workQueue.offer會跟根據(jù)不同的阻塞隊(duì)列從而導(dǎo)致線程池出現(xiàn)不同的線程添加機(jī)制,我會在2.1中著重說不同阻塞隊(duì)列的情況折剃。
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
           //如果在我們添加到阻塞隊(duì)列之后另假,狀態(tài)不是RUNNING狀態(tài),會將當(dāng)前任務(wù)從阻塞隊(duì)列移除怕犁,并拒絕這次任務(wù)
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //這種情況是由于corePoolSize允許為0边篮,當(dāng)corePoolSize為0時,第一次會運(yùn)行到這步奏甫,并添加線程到線程池中戈轿。當(dāng)corePoolSize等于0時,會相當(dāng)于只在核心線程池中添加一個線程用于消費(fèi)阻塞隊(duì)列的任務(wù)阵子,這里也會在2.1結(jié)合不同阻塞隊(duì)列說
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
2.1 不同阻塞隊(duì)列對于線程池添加的影響思杯。(這里建議先看過上面推薦的博客,并了解了核心線程池中的workers是什么以及線程池的流程)
Paste_Image.png

workers其實(shí)就是存儲這里的MaxPool中包含的所有的工作線程的一個HashSet

workQueue.offer其實(shí)就是要將任務(wù)添加到阻塞隊(duì)列中挠进,如果能夠添加則返回true并添加到阻塞隊(duì)列中色乾,否則返回false。
addWorker這個步驟其實(shí)就是要向workers中創(chuàng)建一個新的線程用于消費(fèi)阻塞隊(duì)列中的任務(wù)领突。
但是對于不同的阻塞隊(duì)列杈湾,offer的行為是不同的。
LinkedBlockingQueue攘须,當(dāng)我們初始化的時候沒有給他初始容量,那么這里殴泰,他每次offer都可以添加到我們的阻塞隊(duì)列中于宙,因?yàn)長inkedBlockingQueue是基于鏈表結(jié)構(gòu)的無界阻塞隊(duì)列。那么我們?nèi)绻鹀orePoolSize不是0悍汛,則相當(dāng)于只有當(dāng)前workers中只有CorePool捞魁,當(dāng)workerCountOf(c) > corePoolSize的時候,我們只是向阻塞隊(duì)列中添加任務(wù)离咐,供之后線程消費(fèi)谱俭,而不會再添加新的worker到workers了奉件,所以這個時候的MaxPool和CorePool是一樣大的,maxmumPoolSize參數(shù)也就沒有了意義昆著。如果corePoolSize是0县貌,則相當(dāng)于只有一個線程在線程池中,之后的任務(wù)都直接進(jìn)入到阻塞隊(duì)列
LinkedBlockingQueue賦予了初始化容量凑懂,那么我的理解是和ArrayBlockingQueue作用是一樣的煤痕。當(dāng)我們的數(shù)量達(dá)到了核心線程數(shù),接下來會向阻塞隊(duì)列中添加任務(wù)接谨,當(dāng)我們的阻塞隊(duì)列也滿了摆碉。則再創(chuàng)建新的worker加入到workers中,當(dāng)達(dá)到最大線程數(shù)時脓豪,最后會reject巷帝。
當(dāng)我們當(dāng)前的線程池核心線程數(shù)大小小于corePoolSize的時候,每次都會創(chuàng)建新的woker來執(zhí)行扫夜,當(dāng)我們等于核心線程數(shù)的時候楞泼,如果這個時候存在空閑的worker,那么會直接使用空閑的worker執(zhí)行历谍,當(dāng)沒有空閑worker的時候會向阻塞隊(duì)列中添加command
SynchronousQueue现拒,擴(kuò)展先閱讀下http://ifeve.com/java-synchronousqueue/.SynchronouseQueue主要是用來做信號量方面的應(yīng)用的,Excutors.newCachedThreadPool就是用的這種方式從而達(dá)到緩存線程池的作用望侈。
這里的SynchronouseQueue用的很精妙.
offer不是每回都返回false印蔬,而是當(dāng)我們當(dāng)前的可用的worker隊(duì)列中,如果不存在可用的worker的時候才會返回false脱衙,如果存在可用的worker的時候侥猬,會返回 true,這是因?yàn)楫?dāng)我們worker執(zhí)行完當(dāng)前work的任務(wù)的時候捐韩,我們回去在繼續(xù)getTask退唠,發(fā)現(xiàn)task不存在的時候,我們會去調(diào)用workQueue.take或poll,從而阻塞在這里荤胁,當(dāng)我們有可用woker的時候瞧预,相當(dāng)于阻塞隊(duì)列存在一個待消費(fèi)的take,這個時候offer會返回true

因?yàn)橹耙恢睂Σ煌?duì)列對線程池運(yùn)行有什么影響不是很理解仅政,這一部分是我經(jīng)過測試并看了一部分源碼得出的一些理解垢油,有問題希望大家能提出來。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末圆丹,一起剝皮案震驚了整個濱河市滩愁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辫封,老刑警劉巖硝枉,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廉丽,死亡現(xiàn)場離奇詭異,居然都是意外死亡妻味,警方通過查閱死者的電腦和手機(jī)正压,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弧可,“玉大人蔑匣,你說我怎么就攤上這事∽厮校” “怎么了裁良?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長校套。 經(jīng)常有香客問我价脾,道長,這世上最難降的妖魔是什么笛匙? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任侨把,我火速辦了婚禮,結(jié)果婚禮上妹孙,老公的妹妹穿的比我還像新娘秋柄。我一直安慰自己,他們只是感情好蠢正,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布骇笔。 她就那樣靜靜地躺著,像睡著了一般嚣崭。 火紅的嫁衣襯著肌膚如雪笨触。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天雹舀,我揣著相機(jī)與錄音芦劣,去河邊找鬼。 笑死说榆,一個胖子當(dāng)著我的面吹牛虚吟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播签财,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼稍味,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荠卷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤烛愧,失蹤者是張志新(化名)和其女友劉穎油宜,沒想到半個月后掂碱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慎冤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年疼燥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚁堤。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡醉者,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出披诗,到底是詐尸還是另有隱情撬即,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布呈队,位于F島的核電站剥槐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宪摧。R本人自食惡果不足惜粒竖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望几于。 院中可真熱鬧蕊苗,春花似錦、人聲如沸沿彭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膝蜈。三九已至锅移,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饱搏,已是汗流浹背非剃。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留推沸,地道東北人备绽。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像鬓催,于是被迫代替她去往敵國和親肺素。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容