線程池主要解決兩個(gè)問題:
1舞骆、 當(dāng)執(zhí)行大量異步任務(wù)時(shí)線程池能夠提供很好的性能廷没。
2糊饱、 線程池提供了一種資源限制和管理的手段,比如可以限制線程的個(gè)數(shù)颠黎,動(dòng)態(tài)新增線程等另锋。
線程池體系
1)Executor 是線程池最頂層的接口,在 Executor 中只有一個(gè) execute 方法狭归,用于執(zhí)行任務(wù)夭坪。至于線程的創(chuàng)建、調(diào)度等細(xì)節(jié)由子類實(shí)現(xiàn)过椎。
2)ExecutorService 繼承并拓展了 Executor室梅,在 ExecutorService 內(nèi)部提供了更全面的任務(wù)提交機(jī)制以及線程池關(guān)閉方法。
3)ThreadPoolExecutor 是 ExecutorService 的默認(rèn)實(shí)現(xiàn)疚宇,所謂的線程池機(jī)制也大多封裝在此類當(dāng)中亡鼠,因此它是本課時(shí)分析的重點(diǎn)。
4)ScheduledExecutorService 繼承自 ExecutorService敷待,增加了定時(shí)任務(wù)相關(guān)方法间涵。
5)ScheduledThreadPoolExecutor 繼承自 ThreadPoolExecutor,并實(shí)現(xiàn)了 ScheduledExecutorService 接口讼撒。
6)ForkJoinPool 是一種支持任務(wù)分解的線程池浑厚,一般要配合可分解任務(wù)接口 ForkJoinTask 來使用。
在ThreadPoolExecutor中根盒,有一個(gè)內(nèi)部類——Work钳幅,它是繼承AbstractQueuedSynchronizer(AQS)類,實(shí)現(xiàn)了Runnable接口的類炎滞。也是實(shí)現(xiàn)線程池的核心敢艰。具體AQS類的源碼解析,請(qǐng)參考上一篇文章《AQS(Abstract Queued Synchronizer)源碼分析》册赛。
創(chuàng)建線程
? ? ? ??ThreadPoolExecutor初始化方法如下:
public ThreadPoolExecutor(int corePoolSize,
? ? ? ? ? ? ? ? ? ? ? ? ? int maximumPoolSize,
? ? ? ? ? ? ? ? ? ? ? ? ? long keepAliveTime,
? ? ? ? ? ? ? ? ? ? ? ? ? TimeUnit unit,
? ? ? ? ? ? ? ? ? ? ? ? ? BlockingQueueworkQueue,
? ? ? ? ? ? ? ? ? ? ? ? ? ThreadFactory threadFactory,
? ? ? ? ? ? ? ? ? ? ? ? ? RejectedExecutionHandler handler)?
參數(shù)說明:
????????corePoolSize:表示核心線程數(shù)量钠导。
????????maximumPoolSize:表示線程池最大能夠容納同時(shí)執(zhí)行的線程數(shù)震嫉,必須大于或等于 1。如果和 corePoolSize 相等即是固定大小線程池牡属。
????????keepAliveTime:表示線程池中的線程空閑時(shí)間票堵,當(dāng)空閑時(shí)間達(dá)到此值時(shí),線程會(huì)被銷毀直到剩下 corePoolSize 個(gè)線程逮栅。
????????unit:用來指定 keepAliveTime 的時(shí)間單位悴势,有 MILLISECONDS、SECONDS措伐、MINUTES特纤、HOURS 等。
????????workQueue:等待隊(duì)列侥加,BlockingQueue 類型捧存。當(dāng)請(qǐng)求任務(wù)數(shù)大于 corePoolSize 時(shí),任務(wù)將被緩存在此 BlockingQueue 中担败。
????????threadFactory:線程工廠昔穴,線程池中使用它來創(chuàng)建線程,如果傳入的是 null氢架,則使用默認(rèn)工廠類 DefaultThreadFactory傻咖。
????????handler:執(zhí)行拒絕策略的對(duì)象。當(dāng) workQueue 滿了之后并且活動(dòng)線程數(shù)大于 maximumPoolSize 的時(shí)候岖研,線程池通過該策略處理請(qǐng)求。拒絕策略如下:
注意:當(dāng) ThreadPoolExecutor 的 allowCoreThreadTimeOut 設(shè)置為 true 時(shí)警检,核心線程超時(shí)后也會(huì)被銷毀孙援。
禁止使用 Executors
????????為了方便開發(fā)者可以更方便的使用線程池,JDK 中給我們提供了一個(gè)線程池的工廠類—Executors扇雕。在 Executors 中定義了多個(gè)靜態(tài)方法拓售,用來創(chuàng)建不同配置的線程池。常見有以下幾種镶奉。
? ??????newSingleThreadExecutor:創(chuàng)建一個(gè)單線程化的線程池础淤,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按先進(jìn)先出的順序執(zhí)行哨苛。
? ??????newCachedThreadPool:創(chuàng)建一個(gè)可緩存線程池鸽凶,如果線程池長度超過處理需要,可靈活回收空閑線程建峭,若無可回收玻侥,則新建線程。
? ??????newFixedThreadPool:創(chuàng)建一個(gè)固定數(shù)目的亿蒸、可重用的線程池凑兰。
? ? ? ? 那為什么要禁止呢掌桩?主要是因?yàn)槿菀壮霈F(xiàn)OOM。以下是Executors中的部分創(chuàng)建線程池的源碼:
? ? ? ? 1姑食、newCachedThreadPool?緩存線程池的最大線程數(shù)為 Integer 最大值波岛。當(dāng)核心線程耗時(shí)很久,線程池會(huì)嘗試創(chuàng)建新的線程來執(zhí)行提交的任務(wù)音半,當(dāng)內(nèi)存不足時(shí)就會(huì)報(bào)無法創(chuàng)建線程的錯(cuò)誤则拷。
? ? ? ? 2、newSingleThreadExecutor和newFixedThreadPool傳入的是一個(gè)無界的阻塞隊(duì)列祟剔,理論上可以無限添加任務(wù)到線程池隔躲。
以上兩種情況如果發(fā)生在生產(chǎn)環(huán)境將會(huì)是致命的。因此在創(chuàng)建線程池時(shí)物延,盡量不要用工具類Executors快速創(chuàng)建線程池宣旱。
總結(jié)
? ??????線程池是為了在大量異步任務(wù)時(shí),提供了資源限制和管理的手段叛薯。其中核心是靠ThreadPoolExecutor.Work(AQS子類)進(jìn)行管理和執(zhí)行的浑吟。盡量不要用工具類Executors創(chuàng)建線程池。