Java中的線程池ThreadPoolExecutor解析
線程池
針對各種池子,比如
- 連接池:用于管理和重復(fù)使用數(shù)據(jù)庫連接,避免頻繁創(chuàng)建和銷毀數(shù)據(jù)庫連接帶來的性能開銷。
- 對象池:用于管理和重復(fù)使用對象,避免頻繁創(chuàng)建和銷毀對象帶來的性能開銷。
- 字符串池:用于管理和重復(fù)使用字符串,避免頻繁創(chuàng)建和銷毀字符串帶來的性能開銷。
- 線程池的話也是一樣的,用于管理和重復(fù)使用線程,避免頻繁創(chuàng)建和銷毀線程帶來的性能開銷。
- 而線程池的工作原理就是相當(dāng)于把任務(wù)提交到一個阻塞隊列里面,如何線程去阻塞隊列里面拿到任務(wù)去執(zhí)行.
ThreadPoolExecutor詳解
首先看看UML圖:
可以看到最頂層的接口是Executor,就是線程池的頂層接口,線程池的作用就是執(zhí)行方法,而Executor方法里面就一個方法: void execute(Runnable command); 這個方法就是線程池最主要的方法,執(zhí)行runnable任務(wù),然后ExecutorService又對線程池的功能進(jìn)行了加強(qiáng),比如可以進(jìn)行管理線程池,且提供了執(zhí)行任務(wù)的能力,比如執(zhí)行異步返回Future結(jié)果的方法,執(zhí)行多個任務(wù)的方法;
ThreadPoolExecutor參數(shù)詳解
最主要的構(gòu)造方法:
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; }
- int corePoolSize 核心線程數(shù)(一般為cpu數(shù)Runtime.getRuntime().availableProcessors())
- int maximumPoolSize 最大線程數(shù)(一般為cpu數(shù)*2)
- long keepAliveTime 存活的時長(<最大線程數(shù),<核心線程數(shù)的)
- TimeUnit 時間單位
- BlockingQueue workQueue 工作隊列
- ThreadFactory threadFactory 線程工廠,創(chuàng)建線程的地方
- RejectedExecutionHandler handler 拒絕策略
- 需要注意的是,maximumPoolSize 是當(dāng)線程隊列滿了,且核心線程都在執(zhí)行中的時候,再提交任務(wù),就不會放到隊列里面,只會新建線程執(zhí)行,如果線程數(shù)量等于了最大線程數(shù)的時候,就會走對應(yīng)的拒絕策略,如果任務(wù)執(zhí)行完,過期時間才會對新增線程有效,當(dāng)然有個方法allowCoreThreadTimeOut,讓核心線程也可以過期(一般不會設(shè)置的),一般工作隊列不會設(shè)置為無限隊列,因為如果隊列無限長可能會造成oom,且最大線程數(shù)就沒用了.
創(chuàng)建線程池的工具類Executors
- newFixedThreadPool
創(chuàng)建固定大小的線程池。核心數(shù)和最大數(shù)是一樣的,任務(wù)如果過多會在隊列中阻塞.如果某個線程因為執(zhí)行異常而結(jié)束,那么線程池會補(bǔ)充一個新線程。
- newWorkStealingPool
1.8新加的線程池,forkJoinPool 可以根據(jù)CPU的核數(shù)并行的執(zhí)行,適合使用在很耗時的操作,可以充分的利用CPU執(zhí)行任務(wù),任務(wù)竊取線程池,不保證執(zhí)行順序,適合任務(wù)耗時差異較大。線程池中有多個線程隊列,有的線程隊列中有大量的比較耗時的任務(wù)堆積,而有的線程隊列卻是空的,就存在有的線程處于饑餓狀態(tài),當(dāng)一個線程處于饑餓狀態(tài)時,它就會去其它的線程隊列中竊取任務(wù)。解決饑餓導(dǎo)致的效率問題。
默認(rèn)創(chuàng)建的并行 level 是 CPU 的核數(shù)。主線程結(jié)束,即使線程池有任務(wù)也會立即停止。
- newSingleThreadExecutor
創(chuàng)建一個單線程的線程池。這個線程池的核心數(shù)和最大數(shù)都是1,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
- newCachedThreadPool
創(chuàng)建一個可緩存的線程池。核心數(shù)是0,最大數(shù)是 Integer.MAX_VALUE,如果一下子任務(wù)很多,且執(zhí)行時間長,容易發(fā)生異常,堆溢出,且執(zhí)行效率降低,并不是線程數(shù)目越多,執(zhí)行越快的,如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。
- newScheduledThreadPool
支持周期性任務(wù)的調(diào)度。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。按道理來說線程池的最大數(shù)是 Integer.MAX_VALUE,但是,線程數(shù)并不會超過核心數(shù)…是固定長度的.
這些方法基本都是創(chuàng)建ThreadPoolExecutor,或者繼承ThreadPoolExecutor,對其進(jìn)行增強(qiáng).
任務(wù)拒絕策略
默認(rèn)的拒絕策略是AbortPolicy,直接拋出異常
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy(); public static class AbortPolicy implements RejectedExecutionHandler { /** * Creates an {@code AbortPolicy}. */ public AbortPolicy() { } /** * Always throws RejectedExecutionException. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
ThreadPoolExecutor.AbortPolicy 丟棄任務(wù)并且拋出- RejectedExecutionException異常。在任務(wù)不能提交的時候,拋出異常,及時反饋程序運(yùn)行狀態(tài)。如果是比較關(guān)鍵的業(yè)務(wù),推薦使用此拒絕策略,這樣子在系統(tǒng)不能承受更大的并發(fā)量的時候,能夠及時通過異常發(fā)現(xiàn)。
ThreadPoolExecutor.DiscardPolicy 丟棄任務(wù),但是不拋出異常。使用此策略,可能會使我們無法發(fā)現(xiàn)系統(tǒng)的異常狀態(tài)。建議是一些無關(guān)緊要的業(yè)務(wù)采用此策略。
ThreadPoolExecutor.DiscardOldestPolicy 丟棄隊列最前面的任務(wù),然后重新提交被拒絕的任務(wù)。
ThreadPoolExecutor.CallerRunsPolicy 由調(diào)用線程(提交任務(wù)的線程)處理該任務(wù)。這種情況是需要讓所有任務(wù)都執(zhí)行完畢,那么就適合大量計算的任務(wù)類型去執(zhí)行,多線程僅僅是增大吞吐量的手段,最終必須要讓每個任務(wù)都執(zhí)行完畢。
到此這篇關(guān)于Java中的線程池ThreadPoolExecutor解析的文章就介紹到這了,更多相關(guān)Java的ThreadPoolExecutor內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+Quartz實現(xiàn)動態(tài)定時任務(wù)
這篇文章主要為大家詳細(xì)介紹了springBoot+Quartz實現(xiàn)動態(tài)定時任務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09