燈下黑钧汹?原來線程池是最典型生產(chǎn)消費(fèi)者模式

線程池:是生產(chǎn)者-消費(fèi)者模型的典型應(yīng)用据某。應(yīng)用程序?qū)⑷蝿?wù)交給線程池,線程池將其放入到BlockingQueue中寄纵。線程池中的已經(jīng)開啟的worker線程會循環(huán)監(jiān)聽BlockingQueue中的任務(wù)來進(jìn)行消費(fèi)鳖敷。

1. 簡述:線程池的設(shè)計(jì)理念

使用Thread開啟線程:

  • 執(zhí)行start()方法。線程才會真正異步的執(zhí)行程拭。
  • 執(zhí)行run()方法定踱,線程同步的執(zhí)行。

當(dāng)然恃鞋,一般我們會執(zhí)行start方法崖媚。

若使用Thread開啟線程:每一次子線程均需要經(jīng)歷創(chuàng)建和銷毀的生命周期亦歉,性能不好。

為了解決這個(gè)問題至扰,JDK設(shè)計(jì)出線程池鳍徽。

1.1 生產(chǎn)消費(fèi)者模型

JDK的BlockingQueue,天生實(shí)現(xiàn)的是生產(chǎn)者-消費(fèi)者模型敢课,即隊(duì)列滿了put隊(duì)列會被阻塞阶祭;隊(duì)列空了后get方法會被阻塞。

work線程將開啟while循環(huán)的監(jiān)聽

線程池中Worker線程開啟后直秆。使用while循環(huán)消費(fèi)BlockingQueue中的Runnable濒募。若while循環(huán)時(shí)得到的任務(wù)為空,那么便去關(guān)閉Worker線程圾结。這也就是最大線程數(shù)超過空閑時(shí)間的核心線程數(shù)能自動回收的原因瑰剃。

image.png

核心線程最大空閑時(shí)間:

核心線程數(shù)的空閑時(shí)間KeepAliveTime。其實(shí)就是阻塞隊(duì)列獲取Running的最大等待時(shí)間筝野。當(dāng)配置了該參數(shù)且超過最大等待時(shí)間晌姚,那么返回一個(gè)null任務(wù)。而worker線程的run方法中的while循環(huán)得到null時(shí)歇竟,便會結(jié)束這個(gè)worker線程挥唠。

poll獲取到的元素為空,那么便會結(jié)束監(jiān)聽焕议,worker線程的run方法執(zhí)行完畢宝磨。

  • get:向阻塞隊(duì)列獲取元素,當(dāng)阻塞隊(duì)列空了之后盅安,put時(shí)會被阻塞唤锉。
  • poll(1,TimeUnit.MILLISECONDS):如果隊(duì)列為空,阻塞一段時(shí)間后依舊為null别瞭,則返回null窿祥。
image.png

當(dāng)返回null時(shí),由“work線程將開啟while循環(huán)的監(jiān)聽”可值蝙寨,將結(jié)束worker線程的監(jiān)聽操作壁肋。

生產(chǎn)者和拒絕策略

生產(chǎn)者向BlockingQueue中放入消息時(shí),并沒有使用put方法籽慢,而是使用的offer方法浸遗。

  • put:向阻塞隊(duì)列填充元素,當(dāng)阻塞隊(duì)列滿了之后箱亿,put時(shí)會被阻塞跛锌。
  • offer:向阻塞隊(duì)列填充元素,當(dāng)阻塞隊(duì)列滿了之后,offer會返回false髓帽。

拒絕策略:因?yàn)閛ffer方法返回false菠赚,說明阻塞隊(duì)列已經(jīng)滿了,若最大線程數(shù)大于核心線程數(shù)郑藏,那么繼續(xù)開啟Worker線程衡查。若開啟的是最大線程數(shù)的Worker線程,那么就會執(zhí)行配置的拒絕策略必盖。

image.png

本質(zhì)上就是一個(gè)內(nèi)存級別的RabbitMQ

1.2 線程池的原理簡述

  1. 線程池里面的線程為消費(fèi)者線程(worker線程)【消費(fèi)者循環(huán)去處理任務(wù)】拌牲,默認(rèn)情況下,必須有任務(wù)的到來才會觸發(fā)創(chuàng)建消費(fèi)者歌粥。也可以使用prestartAllCoreThreads方法塌忽,在線程池初始化時(shí),將所有的消費(fèi)者全部創(chuàng)建出來失驶。

  2. 消費(fèi)者監(jiān)聽的是BlockingQueue隊(duì)列(默認(rèn)實(shí)現(xiàn)生產(chǎn)消費(fèi)者模式)土居,消費(fèi)者調(diào)用workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)方法拉取任務(wù),若是在指定時(shí)間內(nèi)獲取不到任務(wù)嬉探,便會將自己注銷掉(也就是結(jié)束監(jiān)聽)擦耀。

  3. 生產(chǎn)者向BlockingQueue存入任務(wù)時(shí),使用的是offer方法涩堤,即隊(duì)列滿了之后返回false眷蜓,然后判斷最大線程數(shù)是否在開啟Worker線程以及任務(wù)的拒絕策略

1.3 線程池任務(wù)執(zhí)行流程

  1. 當(dāng)線程池中線程數(shù)量小于corePoolSize定躏,每來一個(gè)任務(wù)账磺,就會創(chuàng)建一個(gè)線程執(zhí)行這個(gè)任務(wù)芹敌。
  2. 當(dāng)前線程池線程數(shù)量大于等于corePoolSize痊远,則每來一個(gè)任務(wù)。會嘗試將其添加到任務(wù)緩存隊(duì)列中氏捞,若是添加成功碧聪,則該任務(wù)會等待線程將其取出去執(zhí)行;若添加失斠壕ァ(一般來說任務(wù)緩存隊(duì)列已滿)逞姿,則會嘗試創(chuàng)建新的線程執(zhí)行。
  3. 當(dāng)前線程池線程數(shù)量等于maximumPoolSize捆等,則會采取任務(wù)拒絕策略進(jìn)行處理滞造。
  4. 當(dāng)前線程池線程數(shù)量大于corePoolSize,如果某線程空閑時(shí)間超過keepAliveTime栋烤,線程將會被終止谒养,直到不大于corePoolSize數(shù)量。如果允許為核心池(corePoolSize)中的線程設(shè)置存活時(shí)間明郭,那么核心池中的線程空閑時(shí)間超過keepAliveTime买窟,線程也會被終止丰泊。

1.4 拒絕策略:一個(gè)也不放棄

有時(shí)候,我們不想丟棄任務(wù)始绍,且將生產(chǎn)者(主線程)阻塞瞳购,那么如何實(shí)現(xiàn)拒絕策略?

上文我們得知亏推,生產(chǎn)者放入queue時(shí)使用的是offer方法学赛,當(dāng)阻塞隊(duì)列滿了之后,直接返回false径簿。我們可以采用put的方式罢屈,將主線程阻塞。不在向BlockingQueue中填充任務(wù)篇亭。

    ThreadPoolExecutor executor2 = new ThreadPoolExecutor(1, 1, 100
            , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(50),((r, executor) -> {
        try {
            //阻塞主線程
            executor.getQueue().put(r);
        } catch (InterruptedException e) {
        }     
    }));

詳細(xì)源碼分析

JAVA并發(fā)(12)— Lock實(shí)現(xiàn)生產(chǎn)者消費(fèi)者
JAVA并發(fā)(13)— ThreadPoolExecutor的實(shí)現(xiàn)原理(源碼分析)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缠捌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子译蒂,更是在濱河造成了極大的恐慌曼月,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柔昼,死亡現(xiàn)場離奇詭異哑芹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)捕透,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門聪姿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乙嘀,你說我怎么就攤上這事末购。” “怎么了虎谢?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵盟榴,是天一觀的道長。 經(jīng)常有香客問我婴噩,道長擎场,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任几莽,我火速辦了婚禮迅办,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘章蚣。我一直安慰自己站欺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著镊绪,像睡著了一般匀伏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝴韭,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天够颠,我揣著相機(jī)與錄音,去河邊找鬼榄鉴。 笑死履磨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的庆尘。 我是一名探鬼主播剃诅,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驶忌!你這毒婦竟也來了矛辕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤付魔,失蹤者是張志新(化名)和其女友劉穎聊品,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體几苍,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翻屈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妻坝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伸眶。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刽宪,靈堂內(nèi)的尸體忽然破棺而出厘贼,到底是詐尸還是另有隱情,我是刑警寧澤纠屋,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布涂臣,位于F島的核電站盾计,受9級特大地震影響售担,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜署辉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一族铆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哭尝,春花似錦哥攘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耕姊。三九已至,卻和暖如春栅葡,著一層夾襖步出監(jiān)牢的瞬間茉兰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工欣簇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留规脸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓熊咽,卻偏偏與公主長得像莫鸭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子横殴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

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