阿里巴巴建議的線程池創(chuàng)建方式,你用上了嗎?
點擊關注公眾號,Java干貨及時送達
作者:打不死Gin
來源:blog.csdn.net/dabusiGin/article/details/105327873
Executor是不建議的
Executors類為我們提供了各種類型的線程池,經(jīng)常使用的工廠方法有:
public?static?ExecutorService?newSingleThreadExecutor()
public?static?ExecutorService?newFixedThreadPool(int?nThreads)
public?static?ExecutorService?newCachedThreadPool()
public?static?ScheduledExecutorService?newSingleThreadScheduledExecutor()
public?static?ScheduledExecutorService?newScheduledThreadPool(int?corePoolSize)
書寫一段很簡單的測試代碼:
public?class?ThreadDemo?{
?public?static?void?main(String[]?args)?{
??ExecutorService?es?=?Executors.newSingleThreadExecutor();
?}
}
當我們用阿里巴巴的P3C檢查代碼時,會被教育的?。。。?/p>
阿里爸爸是不允許這么創(chuàng)建線程池的,上面的警告寫的很明確“線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規(guī)則,規(guī)避資源耗盡的風險?!保≒S:很難得在編譯器中看到中文提示,對于英語不好的同學來說,簡直是福音,喜極而泣!?。。。?/p>
強制使用ThreadPoolExecutor
我們使用ThreadPoolExecutor創(chuàng)建線程池:
public?class?ThreadDemo?{
?public?static?void?main(String[]?args)?{
??ExecutorService?es?=?new?ThreadPoolExecutor(1,?1,?0L,?TimeUnit.MILLISECONDS,
????new?LinkedBlockingQueue(10),?Executors.defaultThreadFactory(),
????new?ThreadPoolExecutor.DiscardPolicy());
?}
}
此時,再用P3C檢查代碼,終于沒有報錯了。
在華麗的分隔符之后,我們還是有必要從JDK源碼的層面深挖一下其中的原理。
首先是靜態(tài)方法newSingleThreadExecutor()、newFixedThreadPool(int nThreads)、newCachedThreadPool()。我們來看一下其源碼實現(xiàn)(基于JDK8)。
public?static?ExecutorService?newSingleThreadExecutor()?{
????????return?new?FinalizableDelegatedExecutorService
????????????(new?ThreadPoolExecutor(1,?1,
????????????????????????????????????0L,?TimeUnit.MILLISECONDS,
????????????????????????????????????new?LinkedBlockingQueue()));
}
public?static?ExecutorService?newFixedThreadPool(int?nThreads)?{
????????return?new?ThreadPoolExecutor(nThreads,?nThreads,
??????????????????????????????????????0L,?TimeUnit.MILLISECONDS,
??????????????????????????????????????new?LinkedBlockingQueue());
}
public?static?ExecutorService?newCachedThreadPool()?{
????????return?new?ThreadPoolExecutor(0,?Integer.MAX_VALUE,
??????????????????????????????????????60L,?TimeUnit.SECONDS,
??????????????????????????????????????new?SynchronousQueue());
}
通過查看源碼我們知道上述三種靜態(tài)方法的內(nèi)部實現(xiàn)均使用了ThreadPoolExecutor類。難怪阿里爸爸會建議通過ThreadPoolExecutor的方式實現(xiàn),原來Executors類的靜態(tài)方法也是用的它,只不過幫我們配了一些參數(shù)而已。
第二是ThreadPoolExecutor類的構造方法。既然現(xiàn)在要直接使用ThreadPoolExecutor類了,那么其中的初始化參數(shù)就要我們自己配了,了解其構造方法勢在必行。
ThreadPoolExecutor類一共有四個構造方法,我們只需要了解之中的一個就可以了,因為其他三種構造方法只是幫我們配置了一些默認參數(shù),最后還是調(diào)用了它。
public?ThreadPoolExecutor(int?corePoolSize,
????????????int?maximumPoolSize,
????????????long?keepAliveTime,
????????????TimeUnit?unit,
????????????BlockingQueue?workQueue,
????????????ThreadFactory?threadFactory,
????????????RejectedExecutionHandler?handler)
其中的參數(shù)含義是:
corePoolSize:線程池中的線程數(shù)量;maximumPoolSize:線程池中的最大線程數(shù)量;keepAliveTime:當線程池線程數(shù)量超過corePoolSize時,多余的空閑線程會在多長時間內(nèi)被銷毀;unit:keepAliveTime的時間單位;workQueue:任務隊列,被提交但是尚未被執(zhí)行的任務;threadFactory:線程工廠,用于創(chuàng)建線程,一般情況下使用默認的,即Executors類的靜態(tài)方法defaultThreadFactory();handler:拒絕策略。當任務太多來不及處理時,如何拒絕任務。
對于這些參數(shù)要有以下了解:
corePoolSize與maximumPoolSize的關系
首先corePoolSize肯定是 <= maximumPoolSize。
其他關系如下:
若當前線程池中線程數(shù) < corePoolSize,則每來一個任務就創(chuàng)建一個線程去執(zhí)行; 若當前線程池中線程數(shù) >= corePoolSize,會嘗試將任務添加到任務隊列。如果添加成功,則任務會等待空閑線程將其取出并執(zhí)行; 若隊列已滿,且當前線程池中線程數(shù) < maximumPoolSize,創(chuàng)建新的線程; 若當前線程池中線程數(shù) >= maximumPoolSize,則會采用拒絕策略(JDK提供了四種,下面會介紹到)。
注意:關系3是針對的有界隊列,無界隊列永遠都不會滿,所以只有前2種關系。
workQueue
參數(shù)workQueue是指提交但未執(zhí)行的任務隊列。若當前線程池中線程數(shù)>=corePoolSize時,就會嘗試將任務添加到任務隊列中。主要有以下幾種:
SynchronousQueue:直接提交隊列。SynchronousQueue沒有容量,所以實際上提交的任務不會被添加到任務隊列,總是將新任務提交給線程執(zhí)行,如果沒有空閑的線程,則嘗試創(chuàng)建新的線程,如果線程數(shù)量已經(jīng)達到最大值(maximumPoolSize),則執(zhí)行拒絕策略。LinkedBlockingQueue:無界的任務隊列。當有新的任務來到時,若系統(tǒng)的線程數(shù)小于corePoolSize,線程池會創(chuàng)建新的線程執(zhí)行任務;當系統(tǒng)的線程數(shù)量等于corePoolSize后,因為是無界的任務隊列,總是能成功將任務添加到任務隊列中,所以線程數(shù)量不再增加。若任務創(chuàng)建的速度遠大于任務處理的速度,無界隊列會快速增長,直到內(nèi)存耗盡。
handler
JDK內(nèi)置了四種拒絕策略:
DiscardOldestPolicy策略:丟棄任務隊列中最早添加的任務,并嘗試提交當前任務;CallerRunsPolicy策略:調(diào)用主線程執(zhí)行被拒絕的任務,這提供了一種簡單的反饋控制機制,將降低新任務的提交速度。DiscardPolicy策略:默默丟棄無法處理的任務,不予任何處理。AbortPolicy策略:直接拋出異常,阻止系統(tǒng)正常工作。
往 期 推 薦
1、精品 IDEA 插件大匯總!值得收藏 2、為什么 jsp 還沒有淘汰??? 3、Redis 作者:每天花6小時搞開源,頂不住了! 4、rm 好兇殘,太 TM 嚇人了! 5、上午寫了一段代碼,下午就被開除了,奇怪的知識又增加了! 6、21 款 yyds 的 IDEA插件 7、真香!用 IDEA 神器看源碼,效率真高! 點分享
點收藏
點點贊
點在看





