阿里規(guī)范要求不能使用Executors創(chuàng)建線程

什么是線程池

線程池可以通過池看出來是一個(gè)資源集解取,任何池的作用都大同小異,主要是用來減少資源創(chuàng)建拔疚、初始化的系統(tǒng)開銷。

創(chuàng)建線程很“貴”嗎

是的既荚。創(chuàng)建線程的代價(jià)是昂貴的草雕。

我們都知道系統(tǒng)中的每個(gè)進(jìn)程有自己獨(dú)立的內(nèi)存空間,而被稱為輕量級(jí)進(jìn)程的線程也是需要的固以。

在JVM中默認(rèn)一個(gè)線程需要使用256k~1M(取決于32位還是64位操作系統(tǒng))的內(nèi)存墩虹。(具體的數(shù)組我們不深究,因?yàn)殡S著JVM版本的變化這個(gè)默認(rèn)值隨時(shí)可能發(fā)生變更憨琳,我們只需要知道線程是需要占用內(nèi)存的)

許多文章會(huì)將上下文切換诫钓、CPU調(diào)度列入其中,這邊不將線程調(diào)度列入是因?yàn)樗咧械木€程不會(huì)被調(diào)度(OS控制)篙螟,如果不是睡眠中的線程那么是一定需要被調(diào)度的菌湃。

但在JVM中除了創(chuàng)建時(shí)的內(nèi)存消耗,還會(huì)給GC帶來壓力遍略,如果頻繁創(chuàng)建線程那么相對(duì)的GC的時(shí)候也需要回收對(duì)應(yīng)的線程惧所。

線程池的機(jī)制

可以看到線程池是一種重復(fù)利用線程的技術(shù),線程池的主要機(jī)制就是保留一定的線程數(shù)在沒有事情做的時(shí)候使之睡眠绪杏,當(dāng)有活干的時(shí)候拿一個(gè)線程去運(yùn)行下愈。

這些牽扯到線程池實(shí)現(xiàn)的具體策略。

線程池的好處

第一:降低資源消耗蕾久。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗势似。

第二:提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí)僧著,任務(wù)可以不需要的等到線程創(chuàng)建就能立即執(zhí)行履因。

第三:提高線程的可管理性。線程是稀缺資源盹愚,如果無限制的創(chuàng)建栅迄,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性皆怕,使用線程池可以進(jìn)行統(tǒng)一的分配毅舆,調(diào)優(yōu)和監(jiān)控。但是要做到合理的利用線程池端逼,必須對(duì)其原理了如指掌

線程池的主要工作流程

從上圖我們可以看出朗兵,當(dāng)提交一個(gè)新任務(wù)到線程池時(shí),線程池的處理流程如下:

首先線程池判斷基本線程池是否已滿顶滩?沒滿,創(chuàng)建一個(gè)工作線程來執(zhí)行任務(wù)寸爆。滿了礁鲁,則進(jìn)入下個(gè)流程盐欺。

其次線程池判斷工作隊(duì)列是否已滿?沒滿仅醇,則將新提交的任務(wù)存儲(chǔ)在工作隊(duì)列里冗美。滿了,則進(jìn)入下個(gè)流程析二。

最后線程池判斷整個(gè)線程池是否已滿粉洼?沒滿,則創(chuàng)建一個(gè)新的工作線程來執(zhí)行任務(wù)叶摄,滿了属韧,則交給飽和策略來處理這個(gè)任務(wù)。

線程池的創(chuàng)建

我們可以通過ThreadPoolExecutor來創(chuàng)建一個(gè)線程池蛤吓。

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,

keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

創(chuàng)建一個(gè)線程池需要輸入幾個(gè)參數(shù):

1宵喂、corePoolSize - 線程池核心池的大小。

2会傲、maximumPoolSize - 線程池的最大線程數(shù)锅棕。

3、keepAliveTime - 當(dāng)線程數(shù)大于核心時(shí)淌山,此為終止前多余的空閑線程等待新任務(wù)的最長(zhǎng)時(shí)間裸燎。

4、unit - keepAliveTime 的時(shí)間單位泼疑。

5顺少、workQueue - 用來儲(chǔ)存等待執(zhí)行任務(wù)的隊(duì)列。

6王浴、threadFactory - 線程工廠脆炎。

7、handler - 拒絕策略氓辣。

corePoolSize:核心池的大小秒裕,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后钞啸,默認(rèn)情況下几蜻,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù)体斩,除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法梭稚,從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思絮吵,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程弧烤。默認(rèn)情況下,在創(chuàng)建了線程池后蹬敲,線程池中的線程數(shù)為0暇昂,當(dāng)有任務(wù)來之后莺戒,就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后急波,就會(huì)把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中从铲;

maximumPoolSize:線程池最大線程數(shù),這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù)澄暮,它表示在線程池中最多能創(chuàng)建多少個(gè)線程名段;

keepAliveTime:表示線程沒有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。默認(rèn)情況下泣懊,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)伸辟,keepAliveTime才會(huì)起作用,直到線程池中的線程數(shù)不大于corePoolSize嗅定,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí)自娩,如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止渠退,直到線程池中的線程數(shù)不超過corePoolSize忙迁。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí)碎乃,keepAliveTime參數(shù)也會(huì)起作用姊扔,直到線程池中的線程數(shù)為0;

unit:參數(shù)keepAliveTime的時(shí)間單位梅誓,有7種取值恰梢。TimeUnit.DAYS、TimeUnit.HOURS梗掰、TimeUnit.MINUTES嵌言、TimeUnit.SECONDS、TimeUnit.MILLISECONDS及穗、TimeUnit.MICROSECONDS摧茴、TimeUnit.NANOSECONDS

workQueue:一個(gè)阻塞隊(duì)列,用來存儲(chǔ)等待執(zhí)行的任務(wù)埂陆,這個(gè)參數(shù)的選擇也很重要苛白,會(huì)對(duì)線程池的運(yùn)行過程產(chǎn)生重大影響,一般來說焚虱,這里的阻塞隊(duì)列有以下幾種選擇:ArrayBlockingQueue购裙、LinkedBlockingQueue、SynchronousQueue鹃栽。?

ArrayBlockingQueue和PriorityBlockingQueue使用較少躏率,一般使用LinkedBlockingQueue和SynchronousQueue。線程池的排隊(duì)策略與BlockingQueue有關(guān)。

threadFactory:線程工廠禾锤,主要用來創(chuàng)建線程私股;

handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略摹察,有以下四種取值:?

ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常恩掷。?

ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常供嚎。?

ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù)黄娘,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)?

ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

當(dāng)然也可以根據(jù)應(yīng)用場(chǎng)景需要來實(shí)現(xiàn)RejectedExecutionHandler接口自定義策略。如記錄日志或持久化不能處理的任務(wù)克滴。

線程池不允許使用Executors去創(chuàng)建

線程池不允許使用Executors去創(chuàng)建逼争,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則劝赔,規(guī)避資源耗盡的風(fēng)險(xiǎn)誓焦。 說明:Executors各個(gè)方法的弊端:

1)newFixedThreadPool和newSingleThreadExecutor

主要問題是堆積的請(qǐng)求處理隊(duì)列可能會(huì)耗費(fèi)非常大的內(nèi)存,甚至OOM着帽。

newSingleThreadExecutor

創(chuàng)建一個(gè)單線程的線程池杂伟。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)仍翰。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束赫粥,那么會(huì)有一個(gè)新的線程來替代它。

此線程池保證所有任務(wù)的執(zhí)行順序予借,按照任務(wù)的提交順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行越平。

newFixedThreadPool

創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程灵迫,直到線程達(dá)到線程池的最大大小秦叛。

線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束瀑粥,那么線程池會(huì)補(bǔ)充一個(gè)新線程挣跋。

可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待

2)newCachedThreadPool和newScheduledThreadPool

主要問題是線程數(shù)最大數(shù)是Integer.MAX_VALUE利凑,可能會(huì)創(chuàng)建數(shù)量非常多的線程浆劲,甚至OOM。

newCachedThreadPool

創(chuàng)建一個(gè)可緩存的線程池哀澈。如果線程池的大小超過了處理任務(wù)所需要的線程牌借,

那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí)割按,此線程池又可以智能的添加新線程來處理任務(wù)膨报。

此線程池不會(huì)對(duì)線程池大小做限制

線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。


newScheduledThreadPool

創(chuàng)建一個(gè)定時(shí)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行

圖1


圖2


圖3

線程池創(chuàng)建方式(推薦)

根據(jù)阿里巴巴java開發(fā)規(guī)范现柠,推薦了3種線程池創(chuàng)建方式

推薦方式1:

首先引入:commons-lang3包

推薦方式 2:

首先引入:com.google.guava包

推薦方式 3:

spring配置線程池方式:自定義線程工廠bean需要實(shí)現(xiàn)ThreadFactory院领,可參考該接口的其它默認(rèn)實(shí)現(xiàn)類,使用方式直接注入bean

調(diào)用execute(Runnable task)方法即可

線程使用示例

創(chuàng)建線程工廠方法

package com.guo.test.app.common.util

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

public class AsynExecutorUtil {

public static final ThreadFactoryNAMED_THREAD_FACTORY =new ThreadFactoryBuilder().setNameFormat("test_asyn_executor").build();

? ? public static final ExecutorServiceEXECUTOR? ? ? ? ? ? =new ThreadPoolExecutor(10, 20, 0L,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TimeUnit.MILLISECONDS,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue(1024),

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NAMED_THREAD_FACTORY,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new ThreadPoolExecutor.AbortPolicy());

}

異步使用線程:

AsynExecutorUtil.EXECUTOR.submit(()->testBO.testAsynExecutor(id));

參考:

https://www.cnblogs.com/ants/p/11343657.html

https://www.toutiao.com/i6739759947166253580/

https://blog.csdn.net/weixin_41888813/article/details/90769126

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末够吩,一起剝皮案震驚了整個(gè)濱河市比然,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌周循,老刑警劉巖强法,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亥鬓,死亡現(xiàn)場(chǎng)離奇詭異讽挟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)榛泛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門嚎研,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蓖墅,“玉大人,你說我怎么就攤上這事临扮÷鄯” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵公条,是天一觀的道長(zhǎng)拇囊。 經(jīng)常有香客問我,道長(zhǎng)靶橱,這世上最難降的妖魔是什么寥袭? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮关霸,結(jié)果婚禮上传黄,老公的妹妹穿的比我還像新娘。我一直安慰自己队寇,他們只是感情好膘掰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著佳遣,像睡著了一般识埋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上零渐,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天窒舟,我揣著相機(jī)與錄音,去河邊找鬼诵盼。 笑死惠豺,一個(gè)胖子當(dāng)著我的面吹牛银还,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洁墙,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蛹疯,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了热监?” 一聲冷哼從身側(cè)響起捺弦,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狼纬,沒想到半個(gè)月后羹呵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骂际,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疗琉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歉铝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盈简。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖太示,靈堂內(nèi)的尸體忽然破棺而出柠贤,到底是詐尸還是另有隱情,我是刑警寧澤类缤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布臼勉,位于F島的核電站,受9級(jí)特大地震影響餐弱,放射性物質(zhì)發(fā)生泄漏宴霸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一膏蚓、第九天 我趴在偏房一處隱蔽的房頂上張望瓢谢。 院中可真熱鬧,春花似錦驮瞧、人聲如沸氓扛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽采郎。三九已至,卻和暖如春狂魔,著一層夾襖步出監(jiān)牢的瞬間蒜埋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工毅臊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留理茎,地道東北人黑界。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像皂林,于是被迫代替她去往敵國(guó)和親朗鸠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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