怎么在java項(xiàng)目中自定義線程池?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站制作、成都網(wǎng)站建設(shè)、高縣網(wǎng)絡(luò)推廣、重慶小程序開發(fā)、高縣網(wǎng)絡(luò)營(yíng)銷、高縣企業(yè)策劃、高縣品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供高縣建站搭建服務(wù),24小時(shí)服務(wù)熱線:13518219792,官方網(wǎng)址:www.cdcxhl.com
使用線程池時(shí),可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其實(shí)我們深入到這些方法里面,就可以看到它們的是實(shí)現(xiàn)方式是這樣的。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
包括其他幾種不同類型的線程池,其實(shí)都是通過 ThreadPoolExecutor這個(gè)核心類來創(chuàng)建的,如果我們要自定義線程池,那么也是通過這個(gè)類來實(shí)現(xiàn)的。
該類有四個(gè)構(gòu)造方法,查看源碼可以看到,頭三個(gè)構(gòu)造方法,其實(shí)都是調(diào)用的第四個(gè)構(gòu)造方法,所以我們就解釋一下第四個(gè)構(gòu)造方法的參數(shù)含義。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize:核心線程池的大小,在線程池被創(chuàng)建之后,其實(shí)里面是沒有線程的。(當(dāng)然,調(diào)用prestartAllCoreThreads()或者prestartCoreThread()方法會(huì)預(yù)創(chuàng)建線程,而不用等著任務(wù)的到來)。當(dāng)有任務(wù)進(jìn)來的時(shí)候,才會(huì)創(chuàng)建線程。當(dāng)線程池中的線程數(shù)量達(dá)到corePoolSize之后,就把任務(wù)放到 緩存隊(duì)列當(dāng)中。(就是 workQueue)。
maximumPoolSize:最大線程數(shù)量是多少。它標(biāo)志著這個(gè)線程池的最大線程數(shù)量。如果沒有最大數(shù)量,當(dāng)創(chuàng)建的線程數(shù)量達(dá)到了 某個(gè)極限值,到最后內(nèi)存肯定就爆掉了。
keepAliveTime:當(dāng)線程沒有任務(wù)時(shí),最多保持的時(shí)間,超過這個(gè)時(shí)間就被終止了。默認(rèn)情況下,只有 線程池中線程數(shù)量 大于 corePoolSize時(shí),keepAliveTime值才會(huì)起作用。也就說說,只有在線程池線程數(shù)量超出corePoolSize了。我們才會(huì)把超時(shí)的空閑線程給停止掉。否則就保持線程池中有 corePoolSize 個(gè)線程就可以了。
Unit:參數(shù)keepAliveTime的時(shí)間單位,就是 TimeUnit類當(dāng)中的幾個(gè)屬性。
如下圖:
workQueue:用來存儲(chǔ)待執(zhí)行任務(wù)的隊(duì)列,不同的線程池它的隊(duì)列實(shí)現(xiàn)方式不同(因?yàn)檫@關(guān)系到排隊(duì)策略的問題)比如有以下幾種
ArrayBlockingQueue:基于數(shù)組的隊(duì)列,創(chuàng)建時(shí)需要指定大小。
LinkedBlockingQueue:基于鏈表的隊(duì)列,如果沒有指定大小,則默認(rèn)值是 Integer.MAX_VALUE。(newFixedThreadPool和newSingleThreadExecutor使用的就是這種隊(duì)列)。
SynchronousQueue:這種隊(duì)列比較特殊,因?yàn)椴慌抨?duì)就直接創(chuàng)建新線程把任務(wù)提交了。(newCachedThreadPool使用的就是這種隊(duì)列)。
threadFactory:線程工廠,用來創(chuàng)建線程。
Handler:拒絕執(zhí)行任務(wù)時(shí)的策略,一般來講有以下四種策略,
(1) ThreadPoolExecutor.AbortPolicy 丟棄任務(wù),并拋出 RejectedExecutionException 異常。
(2) ThreadPoolExecutor.CallerRunsPolicy:該任務(wù)被線程池拒絕,由調(diào)用 execute方法的線程執(zhí)行該任務(wù)。
(3) ThreadPoolExecutor.DiscardOldestPolicy : 拋棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)。
(4) ThreadPoolExecutor.DiscardPolicy,丟棄任務(wù),不過也不拋出異常。
看一個(gè)demo ,示例代碼地址:src/thread_runnable/CustomThreadPool.java
class CustomTask implements Runnable{ private int id; public CustomTask(int id) { this.id = id; } @Override public void run() { // TODO Auto-generated method stub System.out.println("#" + id + " threadId=" + Thread.currentThread().getName() ); try { TimeUnit.MILLISECONDS.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } public class CustomThreadPool { public static void main(String[] args) { // TODO Auto-generated method stub BlockingQueuequeue = new ArrayBlockingQueue<>(10); ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 60, TimeUnit.MICROSECONDS, queue); for (int i=0; i<7; i++){ Runnable task = new CustomTask(i); pool.execute(task); } pool.shutdown(); } }
輸出結(jié)果:
從這個(gè)例子,可以看出,雖然我們有7個(gè)任務(wù),但是實(shí)際上,只有三個(gè)線程在運(yùn)行。
那么當(dāng)我們提交任務(wù)給線程池之后,它的處理策略是什么呢?
(1),如果當(dāng)前線程池線程數(shù)目小于 corePoolSize(核心池還沒滿呢),那么就創(chuàng)建一個(gè)新線程去處理任務(wù)。
(2),如果核心池已經(jīng)滿了,來了一個(gè)新的任務(wù)后,會(huì)嘗試將其添加到任務(wù)隊(duì)列中,如果成功,則等待空閑線程將其從隊(duì)列中取出并且執(zhí)行,如果隊(duì)列已經(jīng)滿了,則繼續(xù)下一步。
(3),此時(shí),如果線程池線程數(shù)量 小于 maximumPoolSize,則創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),否則,那就說明線程池到了最大飽和能力了,沒辦法再處理了,此時(shí)就按照拒絕策略來處理。(就是構(gòu)造函數(shù)當(dāng)中的Handler對(duì)象)。
(4),如果線程池的線程數(shù)量大于corePoolSize,則當(dāng)某個(gè)線程的空閑時(shí)間超過了keepAliveTime,那么這個(gè)線程就要被銷毀了,直到線程池中線程數(shù)量不大于corePoolSize為止。
舉個(gè)通俗易懂的例子,公司要設(shè)立一個(gè)項(xiàng)目組來處理某些任務(wù),hr部門給的人員編制是10個(gè)人(corePoolSize)。同時(shí)給他們專門設(shè)置了一間有15個(gè)座位(maximumPoolSize)的辦公室。最開始的時(shí)候來了一個(gè)任務(wù),就招聘一個(gè)人。就這樣,一個(gè)一個(gè)的招聘,招滿了十個(gè)人,不斷有新的任務(wù)安排給這個(gè)項(xiàng)目組,每個(gè)人也在不停的接任務(wù)干活。不過后來任務(wù)越來越多,十個(gè)人無法處理完了。其他的任務(wù)就只能在走廊外面排隊(duì)了。后來任務(wù)越來越多,走廊的排隊(duì)隊(duì)伍也擠不下。然后只好找找一些臨時(shí)工來幫助完成任務(wù)。因?yàn)檗k公室只有15個(gè)座位,所以它們最多也就只能找5個(gè)臨時(shí)工。可是任務(wù)依舊越來越多,根本處理不完,那沒辦法,這個(gè)項(xiàng)目組只好拒絕再接新任務(wù)。(拒絕的方式就是 Handler),最后任務(wù)漸漸的少了,大家都比較清閑了。所以就決定看大家表現(xiàn),誰(shuí)表現(xiàn)不好,誰(shuí)就被清理出這個(gè)辦公室(空閑時(shí)間超過 keepAliveTime),直到 辦公室只剩下10個(gè)人(corePoolSize),維持固定的人員編制為止。
關(guān)于線程池,ThreadPoolExecutor還提供了一些需要注意的方法:
(1) shutdown(),平滑的關(guān)閉線程池。(如果還有未執(zhí)行完的任務(wù),就等待它們執(zhí)行完)。
(2) shutdownNow()。簡(jiǎn)單粗暴的關(guān)閉線程池。(沒有執(zhí)行完的任務(wù)也直接關(guān)閉)。
(3) setCorePoolSize()。設(shè)置/更改核心池的大小。
(4) setMaximumPoolSize(),設(shè)置/更改線程池中最大線程的數(shù)量限制。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。