話說(shuō)java中的線程池
一、java中創(chuàng)建線程已經(jīng)有了new Thread(), implements Runnable, implements Callable等方法了,為什么還需要使用線程池呢?
一般新的事物的產(chǎn)生,肯定是為了彌補(bǔ)舊事物的不足。
那以上幾種創(chuàng)建線程的方式有什么不足之處呢?
每次使用時(shí)創(chuàng)建線程,無(wú)法控制創(chuàng)建線程的數(shù)量,容易創(chuàng)建出過(guò)量線程從而消耗完內(nèi)存。
創(chuàng)建和銷(xiāo)毀線程要耗費(fèi)時(shí)間并造成資源消耗。
那使用線程池創(chuàng)建線程又有什么好處呢?
? ? 不使用線程池創(chuàng)建線程的壞處,恰好是使用線程池的好處。所以使用線程池的好處是減少在創(chuàng)建和銷(xiāo)毀線程上所消耗的時(shí)間以及系統(tǒng)資源的開(kāi)銷(xiāo),解決資源不足的問(wèn) 題。
那使用線程池創(chuàng)建線程又有什么壞處呢?
手動(dòng)創(chuàng)建線程時(shí),可以創(chuàng)建我們需要的所有線程直到內(nèi)存不足。而使用線程池時(shí),不是想創(chuàng)建多少線程就能創(chuàng)建多少的,因?yàn)槎x線程時(shí)有最大線程數(shù)和隊(duì)列大小等參數(shù)限制。
占用一定的內(nèi)存空間,因?yàn)榫€程池定義后,即使不使用,池中的核心線程還是創(chuàng)建了的,只是沒(méi)有啟動(dòng)而已。
線程越多,CPU的調(diào)度開(kāi)銷(xiāo)越大。
。。。
這樣一看,線程池缺點(diǎn)并不比優(yōu)點(diǎn)少,那怎樣使用才能揚(yáng)長(zhǎng)避短。這就是我們要說(shuō)的下一個(gè)問(wèn)題,線程池的創(chuàng)建。
二、線程池的創(chuàng)建
java的JUC包中的Executors類(lèi)為我們提供了以下四種創(chuàng)建線程池的方法:
Executors.newSingleThreadExecutor(),單線程線程池
Executors.newCachedThreadPool(),緩存線程池
Executors.newFixedThreadPool(),固定線程數(shù)線程池
Executors.newScheduledThreadPool(),周期性線程的線程池
但是以上四種創(chuàng)建線程池的方法不是我們本次的重點(diǎn),因?yàn)榘⒗飆ava開(kāi)發(fā)手冊(cè)中強(qiáng)調(diào):線程池不允許使用 Executors 去創(chuàng)建,而是通過(guò) ThreadPoolExecutor 的方式,這 樣的處理方式讓寫(xiě)的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。
原因:Executors 返回的線程池對(duì)象的弊端如下:?
1) FixedThreadPool 和 SingleThreadPool: 允許的請(qǐng)求隊(duì)列長(zhǎng)度為 Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致 OOM。
2) CachedThreadPool: 允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致 OOM。
好,上面大家可能也看到了,正確的創(chuàng)建線程池的方法是:ThreadPoolExecutor。如下圖所示,細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn)了,其實(shí)以上四種創(chuàng)建線程池的方法,內(nèi)部都是使用的ThreadPoolExecutor,只是每種方法系統(tǒng)幫我們定義了部分參數(shù)而已。

由上可知,日常項(xiàng)目開(kāi)發(fā)中我們使用的創(chuàng)建線程池的方法就是下面這句代碼:
new ThreadPoolExecutor(核心線程數(shù), 最大線程數(shù),?線程工廠,?存活時(shí)間, 存活時(shí)間單位, 任務(wù)隊(duì)列, 拒絕策略);
下面對(duì)線程線程池創(chuàng)建時(shí)的七大參數(shù)做個(gè)說(shuō)明。
三、線程池的七大參數(shù)
核心線程數(shù):核心線程大小??梢岳斫鉃榫€程池的基礎(chǔ)能力,就是只要線程池創(chuàng)建了,就會(huì)有這么多個(gè)線程已創(chuàng)建,隨時(shí)可以獲取并啟動(dòng)執(zhí)行。
最大線程數(shù):線程池最大容量大小
任務(wù)隊(duì)列:任務(wù)隊(duì)列,是一個(gè)阻塞隊(duì)列
存活時(shí)間:線程空閑時(shí),能存活多久
時(shí)間單位:時(shí)間單位
線程工廠:線程池中的線程來(lái)源于這兒
拒絕策略:當(dāng)請(qǐng)求線程數(shù)大于隊(duì)列大小+最大線程數(shù)時(shí)執(zhí)行
這兒有個(gè)點(diǎn)需要注意:一個(gè)線程池能執(zhí)行的任務(wù)數(shù) =?最大線程數(shù) +?任務(wù)隊(duì)列大小,和核心線程數(shù)沒(méi)關(guān)系,因?yàn)樽畲缶€程數(shù)涵蓋了核心線程數(shù)。
這幾個(gè)參數(shù)是怎么相互配合協(xié)作的呢?如下。

這兒可能很多人對(duì)最大線程數(shù)和隊(duì)列的先后順序經(jīng)常搞亂,也就是當(dāng)核心線程數(shù)滿(mǎn)了之后,是先進(jìn)隊(duì)列排隊(duì)還是先按最大線程數(shù)再起線程執(zhí)行。下面講個(gè)小例子幫助記憶:
假如當(dāng)?shù)氐碾娏掷U費(fèi)大廳,有10個(gè)窗口(最大線程數(shù)),今天開(kāi)著4個(gè)窗口(核心線程數(shù)),然后大廳有30張椅子(任務(wù)隊(duì)列)。那你去繳費(fèi)的時(shí)候,如果4個(gè)窗口都有人在繳費(fèi)了,那你是領(lǐng)個(gè)號(hào)在椅子上排隊(duì)等候呢?還是讓工作人員給你再開(kāi)個(gè)窗口辦理業(yè)務(wù),肯定是排隊(duì)嘛,因?yàn)榕抨?duì)對(duì)電力局來(lái)說(shuō)沒(méi)啥損耗,但是再開(kāi)個(gè)窗口確要搭上一個(gè)業(yè)務(wù)員,就是這個(gè)道理。
待續(xù)未完。。。。。。