Java线程池ThreadPoolExecutor
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
本文首發(fā)于個(gè)人微信公眾號(hào)《andyqian》, 關(guān)注免費(fèi)獲取Java學(xué)習(xí)資料
前言
??多線程一直是Java進(jìn)階的必修課。在Java中,我們很早就知道可以通過 Thread 類和 Runnable 接口來實(shí)現(xiàn)多線程。與之有著類似職責(zé)的數(shù)據(jù)庫連接,也可通過JDBC創(chuàng)建與使用。但我們深知無論是數(shù)據(jù)庫連接的創(chuàng)建與銷毀,還是線程的創(chuàng)建與銷毀,都是一件及其消耗性能的事情。為了減少這種情況的發(fā)生,前輩們就在思考,是不是可以復(fù)用已有的數(shù)據(jù)庫連接?減少創(chuàng)建,銷毀動(dòng)作?這就是后來數(shù)據(jù)庫連接池的由來。同樣的,為了復(fù)用線程,也就有了線程池。我一直獨(dú)自暗喜,身為一位幸福的Java程序員,前有Java虛擬機(jī)管理內(nèi)存,后有Doug Lea 大師提供并發(fā)庫,鎖機(jī)制。簡直幸福的不像話,不過幸福歸幸福,該掌握的還是需要掌握的,我們一起來看看今天的主角:ThreadPoolExecutor。
簡介
??在面試過程中,也時(shí)常會(huì)遇到一些關(guān)于線程池的問題,例如:
線程池中核心參數(shù)有哪些?
有沒有自己實(shí)現(xiàn)過線程池?
如果讓你自己實(shí)現(xiàn)線程池,你會(huì)怎么做?
…
這些問題,其實(shí)考核的就是Java線程池的知識(shí),更具體一點(diǎn)就是對(duì)ThreadPoolExector類熟不熟悉,下面代碼是ThreadPoolExector類的全參構(gòu)造函數(shù)。下面我們就一一對(duì)參數(shù)進(jìn)行了解。
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;}其中:
corePoolSize:表示該線程池最小的工作線程數(shù)。默認(rèn)情況下,當(dāng)需要使用時(shí)創(chuàng)建線程,也可以調(diào)用 prestartAllCoreThreads() 方法進(jìn)行預(yù)創(chuàng)建所有的核心線程。
maximumPoolSize:表示該線程池最大的線程數(shù)量,理論上將其設(shè)置為無限大,就會(huì)創(chuàng)建無限多的線程,當(dāng)然,創(chuàng)建線程的數(shù)量最終由系統(tǒng)資源也就是操作系統(tǒng)決定。
keepAliveTime:表示空閑線程的超時(shí)時(shí)間,(單位為納秒)。但在構(gòu)造函數(shù)中,單位與unit 參數(shù)配合使用,最終轉(zhuǎn)換為納秒。
unit:表示空閑線程超時(shí)的時(shí)間單位,可選值有:java.util.concurrent.TimeUnit中的值,SECONDS(秒),MINUTES(分),HOURS(小時(shí)),DAYS(天) 等。
workQueue :表示工作隊(duì)列(其實(shí)是一個(gè)runnable隊(duì)列,在線程池中定義為Worker),其基類為:java.util.concurrent.BlockingQueue。
threadFactory:線程工廠,通常用于創(chuàng)建線程,以及命令規(guī)則。默認(rèn)為: Executors.defaultThreadFactory()。
handler 表示處理策略,當(dāng)workQueue隊(duì)列滿時(shí),以及創(chuàng)建線程錯(cuò)誤時(shí)的處理策略。其基類為 java.util.concurrent.RejectedExecutionHandler。默認(rèn)為:AbortPolicy 策略。
不同組合
??在 java.util.concurrent.Executors類為我們提供了多種組合,其底層還是調(diào)用ThreadPoolExecutor。下面列舉幾個(gè)常用的方法:
1.?newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());} ...特性:線程數(shù)量大小固定,且 corePoolSize 與 maximumPoolSize 數(shù)量相等。當(dāng)線程數(shù)量設(shè)置太少時(shí)。task則會(huì)積壓在LinkedBlockingQueue隊(duì)列中。當(dāng) task 任務(wù)大于Integer.MAX_VALUE時(shí) 則會(huì)有OOM發(fā)生的風(fēng)與之類是的還有newSingleThreadExecutor方法。
2. newCachedThreadPool
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}特性:corePoolSize數(shù)量為0,maximumPoolSize數(shù)量為Integer.MAX_VALUE,也就是說理論上是可以創(chuàng)建Integer.MAX_VALUE個(gè)線程的。keepAiveTime時(shí)間為 60秒。BlockingQueue使用的是SynchronousQueue,由于其沒用容量,意味這每一次put對(duì)應(yīng)著一次take操作,其吞吐量比較高。正因?yàn)槿绱?#xff0c;當(dāng)task到達(dá)一定程度時(shí),可能會(huì)創(chuàng)建許多線程,從而導(dǎo)致OOM,甚至服務(wù)不可用。
?
上述方法其實(shí)是對(duì)ThreadPoolExecutor方法的封裝對(duì)不對(duì),知道了ThreadPoolExecutor的每一個(gè)參數(shù),再來使用這個(gè),就得心應(yīng)手了對(duì)不對(duì)。
規(guī)范
Executors類這么方便,是不是可以直接使用Executors類來創(chuàng)建呢?當(dāng)然可以,但并不建議這樣做。在《阿里Java手冊(cè)》中的并發(fā)處理小節(jié)中有提到:
【強(qiáng)制】線程池不允許使用 Executors 去創(chuàng)建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式可以讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。
說明:Executors 返回的線程池對(duì)象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool :
允許的請(qǐng)求隊(duì)列長度為 Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致 OOM 。
2) CachedThreadPool 和 ScheduledThreadPool :允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE ,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致 OOM 。
在實(shí)際應(yīng)用中,我們應(yīng)該遵守規(guī)范,避免掉一些沒必要的問題。該規(guī)約其最終目的是讓大家能夠更清楚了解線程池的每個(gè)參數(shù),從而達(dá)到能夠在實(shí)際應(yīng)用場景中調(diào)為最優(yōu)組合使用,使其達(dá)到最大性能。同樣的,我們也通過安裝阿里巴巴的規(guī)約插件進(jìn)行自動(dòng)掃描與提醒。在Idea中 File -> Setings -> Plugins -> Browse repositories中搜索『Alibaba Java Coding Guidelines』安裝即可!
小結(jié)
在這篇文章中,算是對(duì)ThreadPoolExector的一個(gè)初步了解。知道了其核心參數(shù),到底是怎么回事。但這還并不夠,且不足以學(xué)以致用,還有很多疑問,如:
ThreadPoolExecutor的原理是怎樣的?
我們?nèi)绾巫远x一個(gè)線程池?
ThreadPoolExecutor在Dubbo中的實(shí)踐
…
這些疑惑都需要一一去揭曉。由于篇幅原因,這些會(huì)作為好幾篇文章進(jìn)行記錄。其目的是能夠?qū)W以致用,面試時(shí)也能得心應(yīng)手。
?
相關(guān)閱讀:
《使用 Mybatis 真心不要偷懶!》
《再談Java 生產(chǎn)神器 BTrace》
《Java 生產(chǎn)神器 ?BTrace》
《重構(gòu)不完全指南!》
?
如果想深入學(xué)習(xí)Java并發(fā)編程,《Java并發(fā)編程的藝術(shù)》這本書是值得閱讀的。當(dāng)然了,如果你讀喜歡電子書,也可以回復(fù)公眾號(hào)消息『Java并發(fā)編程的藝術(shù)』進(jìn)行免費(fèi)獲取!
?
關(guān)注免費(fèi)獲取Java學(xué)習(xí)資料
轉(zhuǎn)載于:https://my.oschina.net/u/1462914/blog/3049668
總結(jié)
以上是生活随笔為你收集整理的Java线程池ThreadPoolExecutor的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ios中的视频采集及参数设置和相机操作
- 下一篇: java美元兑换,(Java实现) 美元