線程池是很常用的并發(fā)框架,幾乎所有需要異步和并發(fā)處理任務(wù)的程序都可用到線程池。
使用線程池的好處如下:
- 降低資源消耗:可重復(fù)利用已創(chuàng)建的線程池,降低創(chuàng)建和銷毀帶來的消耗;
- 提高響應(yīng)速度:任務(wù)到達(dá)時,可立即執(zhí)行,無需等待線程創(chuàng)建;
- 提高線程的可管理性:線程池可對線程統(tǒng)一分配、調(diào)優(yōu)和監(jiān)控。
原理
線程池的原理非常簡單,這里用處理流程來概括:
- 線程池判斷核心池里的線程是否都在執(zhí)行任務(wù),如果不是,創(chuàng)建一個新的線程來執(zhí)行任務(wù);
- 如果核心線程池已滿,則將新任務(wù)存在工作隊列中;
- 如果工作隊列滿了,線程數(shù)量沒有達(dá)到線程池上限的前提下,新建一個線程來執(zhí)行任務(wù);
- 線程數(shù)量達(dá)到上限,則觸發(fā)飽和策略來處理這個任務(wù);
使用工作隊列,是為了盡可能降低線程創(chuàng)建的開銷。工作隊列用阻塞隊列來實現(xiàn)。
阻塞隊列
阻塞隊列(BlockingQueue)是指支持阻塞的插入和移除元素的隊列。
- 阻塞的插入:當(dāng)隊列滿時,阻塞插入元素的線程,直到隊列不滿;
- 阻塞的移除:當(dāng)隊列為空,阻塞移除元素的線程,直到隊列不為空;
原理:使用通知者模式實現(xiàn)。當(dāng)生產(chǎn)者往滿的隊列中添加元素時,會阻塞生產(chǎn)者。消費(fèi)者移除元素時,會通知生產(chǎn)者當(dāng)前隊列可用。
阻塞隊列有以下三種類型,分別是:
- 有界阻塞隊列:ArrayBlockingQueue(數(shù)組),LinkedBlockingQueue(鏈表)
- 無界阻塞隊列:LinkedTransferQueue(鏈表),PriorityBlockingQueue(支持優(yōu)先級排序),DelayQueue(支持延時獲取元素的無界阻塞隊列)
- 同步移交隊列:SynchronousQueue
有界阻塞隊列
主要包括ArrayBlockingQueue(數(shù)組),LinkedBlockingQueue(鏈表)兩種。有界隊列大小與線程數(shù)量大小相互配合,隊列容量大線程數(shù)量小時,可減少上下文切換降低cpu使用率,但是會降低吞吐量。
無界阻塞隊列
比較常用的是LinkedTransferQueue。FixedThreadPool就是用這個實現(xiàn)的。無界阻塞隊列要慎重使用,因為在某些情況,可能會導(dǎo)致大量的任務(wù)堆積到隊列中,導(dǎo)致內(nèi)存飆升。
同步移交隊列
SynchronousQueue。不存儲元素的阻塞隊列,每一個put操作必須等待一個take操作,否則不能繼續(xù)添加元素。用于實現(xiàn)CachedThreadPool線程池。
各個線程池所使用的任務(wù)隊列映射關(guān)系如下:
線程池阻塞隊列
FixedThreadPoolLinkedBlockingQueueSingleThreadExecutorLinkedBlockingQueueCachedThreadExecutorSynchronousQueueScheduledThreadPoolExecutorLinkedBlockingQueue
實現(xiàn)類分析
ThreadPoolExecutor是Java線程池的實現(xiàn)類,是Executor接口派生出來的最核心的類。依賴關(guān)系圖如下:
這里不得不提到Executor框架,該框架包含三大部分,如下:
- 任務(wù)。被執(zhí)行任務(wù)需要實現(xiàn)的接口:Runnable和Callable;
- 任務(wù)執(zhí)行。即上述核心接口Executor以及繼承而來的ExecutorService。ExecutorService派生出如下兩個類:ThreadPoolExecutor:線程池核心實現(xiàn)類;ScheduledThreadPoolExecutor:用來做定時任務(wù);
- 異步計算的結(jié)果。接口Future和實現(xiàn)Future接口的FutureTask類。線程池創(chuàng)建
1
|
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler) |
構(gòu)造方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0 ) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null ) throw new NullPointerException(); this .corePoolSize = corePoolSize; this .maximumPoolSize = maximumPoolSize; this .workQueue = workQueue; this .keepAliveTime = unit.toNanos(keepAliveTime); this .threadFactory = threadFactory; this .handler = handler; } |
參數(shù)說明:
- corePoolSize:核心池的線程數(shù)量;
- workQueue:用于保存任務(wù)的工作隊列;
- maximumPoolSize:最大線程池的大小;
- keepAliveTime:當(dāng)線程數(shù)量大于核心池線程數(shù)量時,keepAliveTime為多余的空閑線程等待新任務(wù)的最長時間,超過這個時間,多余的線程會被終止;
- TimeUnit:keepAliveTime的單位;
- ThreadFactory:線程工廠,可以給線程設(shè)置名字;
- handler:飽和策略。當(dāng)隊列和線程池都滿了,會觸發(fā)飽和策略,來處理新提交的任務(wù)。飽和策略以下幾種:AbortPolicy:直接拋出異常;CallerRunsPolicy:只用調(diào)用者所在線程來運(yùn)行任務(wù);DiscardOldestPolicy:丟棄最近一個任務(wù)并執(zhí)行當(dāng)前任務(wù);DiscardPolicy:不處理,丟棄掉。
使用Executors創(chuàng)建線程池
使用工具類Executors可創(chuàng)建三種類型的線程池:FixedThreadPool、SingleThreadExecutor、CachedThreadPool。本質(zhì)上也是調(diào)用上述構(gòu)造方法。理解了前文的參數(shù)解釋,下面三種線程池也就容易理解了。
FixedThreadPool
可重用固定線程數(shù)的線程池。
1
2
3
4
5
|
public static ExecutorService newFixedThreadPool( int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } |
工作流程如下:
- 如果當(dāng)前運(yùn)行的線程數(shù)少于corePoolSize,則創(chuàng)建新線程來執(zhí)行任務(wù);
- 線程數(shù)等于corePoolSize之后,新任務(wù)加入LinkedBlockingQueue(無界阻塞隊列)。因為最大線程數(shù)maximumPoolSize參數(shù)值等于corePoolSize,不會產(chǎn)生多余線程;
- 線程執(zhí)行完任務(wù)之后會反復(fù)從LinkedBlockingQueue中獲取任務(wù)來執(zhí)行。
SingleThreadExecutor
單個worker線程的線程池
1
2
3
4
5
6
|
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor( 1 , 1 , 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } |
SingleThreadExecutor與FixedThreadPool的區(qū)別在于,maximumPoolSize和corePoolSize都設(shè)置成了1,其它參數(shù)都一樣。
- CachedThreadPool
1
2
3
4
5
|
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor( 0 , Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } |
CachedThreadPool將corePoolSize設(shè)置為0,maximumPoolSize設(shè)置為無限大,同時使用了一個沒有容量的工作隊列SynchronousQueue。這個線程池沒有固定的核心線程,而是根據(jù)需要創(chuàng)建新線程。
工作流程:
- 有新任務(wù)時,主線程執(zhí)行SynchronousQueue.offer操作,空閑線程執(zhí)行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)操作,配對成功則將任務(wù)交給空閑線程執(zhí)行;
- 當(dāng)沒有空閑線程時,上面的配對操作失敗,此時會創(chuàng)建一個新線程來執(zhí)行任務(wù);
- 任務(wù)執(zhí)行完畢后,空閑線程會等待60秒。60秒內(nèi)如果有新任務(wù),就立即執(zhí)行,否則時間一過線程就終止。
線程池關(guān)閉
調(diào)用shutdown或者shutdownNow方法可關(guān)閉線程池。原理是遍歷線程池中所有工作線程,調(diào)用interrupt方法來中斷線程。
- shutdown:將線程置為SHUTDOWN狀態(tài),不能接受新的任務(wù),等待所有任務(wù)執(zhí)行完畢;
- shutdownNow:將線程置為STOP狀態(tài),不能接受新的任務(wù),嘗試去終止正在執(zhí)行的惡任務(wù);
這里涉及到ThreadPoolExecutor中定義的線程的五種狀態(tài)
1
2
3
4
5
6
|
// 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; |
- RUNNING:接受新任務(wù),處理任務(wù);
- SHUTDOWN:不接受新任務(wù),但會把隊列中任務(wù)處理完;
- STOP:不接受新任務(wù),不處理隊列中的任務(wù),并且終止正在處理的任務(wù);
- TIDYING:正在執(zhí)行的任務(wù)和隊列都為空,進(jìn)入該狀態(tài),將要執(zhí)行terminated();
- TERMINATED:所有terminated()方法執(zhí)行完畢,線程池徹底終止。
當(dāng)隊列和正在執(zhí)行的任務(wù)都為空時,由SHUTDOWN轉(zhuǎn)化為TIDYING;當(dāng)正在執(zhí)行的任務(wù)為空,由STOP轉(zhuǎn)化為TIDYING。
本博客從線程池的原理介紹作為切入點,分析了線程池中尤為關(guān)鍵的組件:阻塞隊列。同時分析了線程池的核心實現(xiàn)類ThreadPoolExecutor。以線程池的創(chuàng)建和關(guān)閉的思路,梳理了相關(guān)知識點,包括三種常用線程池介紹以及線程池五種狀態(tài)。
到此這篇關(guān)于Java 線程池全面總結(jié)與詳解的文章就介紹到這了,更多相關(guān)Java 線程池內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/weixin_60707895/article/details/121014487