正因爲我抱着與你相見的但願,我才永遠認爲最崎嶇的路是最好的路。html
線程池是啥子,幹啥使它呀,老子線程使得好好的,非得屢次一舉,哈哈,想必來這裏看這篇文章的都對線程池有點了解。那麼我來整理整理線程池的好處吧。面試
線程的建立和銷燬的開銷是巨大的,而經過線程池的重用大大減小了這些沒必要要的開銷,固然既然少了這麼多消費內存的開銷,其線程執行速度也是日新月異的提高。設計模式
初學新手可能對併發這個詞語比較陌生,特此我也是結合百度百科和必生所學得出最優解釋,萬萬記着併發可跟並行不同。併發
併發:在某個時間段內,多個程序都處在執行和執行完畢之間;但在一個時間點上只有一個程序在運行。頭腦風暴:老鷹媽媽喂小雛鷹食物,小雛鷹不少,而老鷹只有一張嘴,她須要一個個餵過去,到最後每一個小雛鷹均可以吃到,可是在一個時間點裏只能有一個小雛鷹能夠吃到美味的食物。異步
並行:在某個時間段裏,每一個程序按照本身獨立異步的速度執行,程序之間互不干擾。頭腦風暴:這就好似老鷹媽媽決定這樣餵食太費勁因而爲每一個小雛鷹請了個保姆,這樣子在一個時間點裏,每一個小雛鷹均可以同時吃到食物,並且互相不干擾。this
回到線程池,控制線程池的併發數能夠有效的避免大量的線程池爭奪CPU資源而形成堵塞。頭腦風暴:仍是拿老鷹的例子來說,媽媽只有一個,要這麼一個個喂下去,一些餓壞的小雛鷹等不下去了就要破壞規則,搶在靠前餵食的雛鷹面前,而前面的雛鷹也不是吃軟飯的,因而打起來了,場面混亂。老鷹生氣了,這麼不懂事,誰也別吃了,因而形成了最後誰也沒食吃的局面。.net
線程池能夠提供定時、按期、單線程、併發數控制等功能。好比經過ScheduledThreadPool線程池來執行S秒後,每隔N秒執行一次的任務。線程
推薦博客: http://blog.csdn.net/seu_calvin/article/details/52415337
想必看完上面那篇博客,你們可謂讚不絕口,不過可能有些小夥伴仍是記不下來,還有些小夥伴以爲好惡心呀,怎麼都是廁所啥的呀!哈哈彆着急,我來給你們一種好記的辦法。設計
先來說講參數最多的那個構造方法,主要是對那幾個煩人的參數進行分析。code
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ... }
這裏是7個參數(咱們在開發中用的更多的是5個參數的構造方法),OK,那咱們來看看這裏七個參數的含義:
emmmmm…看到那麼多煩人的概念,是否是有點頭大了,我反正是頭大了。
這7個參數中,日常最多用到的是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue.在這裏我主要抽出corePoolSize、maximumPoolSize和workQueue三個參數進行詳解。
maximumPoolSize(最大線程數) = corePoolSize(核心線程數) + noCorePoolSize(非核心線程數)
;
(1)當currentSize<corePoolSize時,沒什麼好說的,直接啓動一個核心線程並執行任務。
(2)當currentSize>=corePoolSize、而且workQueue未滿時,添加進來的任務會被安排到workQueue中等待執行。
(3)當workQueue已滿,可是currentSize<maximumPoolSize時,會當即開啓一個非核心線程來執行任務。
(4)當currentSize>=corePoolSize、workQueue已滿、而且currentSize>maximumPoolSize時,調用handler默認拋出RejectExecutionExpection異常。
什麼currentSize,corePoolSize,maximumPoolSize,workQueue比來比去的都比迷糊了,哈哈,那我舉個燒烤店的例子來想必你們理解起來更快。
夏天了,很熱,因此不少燒烤店都會在外面也佈置座位,分爲室內、室外兩個地方能夠吃燒烤。(室內有空調電視,並且室內比室外燒烤更加優惠,並且外面下着瓢潑大雨因此顧客會首先選擇室內)
corePoolSize(燒烤店室內座位),currentPoolSize(目前到燒烤店的顧客數量),maximumPoolSize(燒烤店室內+室外+侯廳室全部座位),workQueue(燒烤店爲顧客專門設置的侯廳室)
第(1)種,燒烤店人數很少的時候,室內位置不少,你們都其樂融融,開心的坐在室內吃着燒烤,看着世界盃。
第(2)種,生意不錯,室內燒烤店坐無空席,你們都不肯意去外面吃,因而在侯廳室裏呆着,侯廳室位置沒坐滿。
第(3)種,生意興隆,室內、侯廳室都坐無空席,可是顧客太餓了,剩下的人沒辦法只好淋着雨吃燒烤,哈哈,好可憐。
第(4)種,生意爆棚,室內、室外、侯廳室都坐無空席,再有顧客過來直接趕走。
對於workQueue仍是有點陌生的小夥伴。
推薦博客: http://blog.csdn.net/u0127025...
在這裏主要是跟你們分享一種特別容易記住其餘四種線程池的方法,在你們寫代碼,面試時能夠及時想到這四種線程池。
(1)FixedThreadPool:
Fixed中文解釋爲固定。結合在一塊兒解釋固定的線程池,說的更全面點就是,有固定數量線程的線程池。其corePoolSize=maximumPoolSize,且keepAliveTime爲0,適合線程穩定的場所。
(2)SingleThreadPool:
Single中文解釋爲單一。結合在一塊兒解釋單一的線程池,說的更全面點就是,有固定數量線程的線程池,且數量爲一,從數學的角度來看SingleThreadPool應該屬於FixedThreadPool的子集。其corePoolSize=maximumPoolSize=1,且keepAliveTime爲0,適合線程同步操做的場所。
(3)CachedThreadPool:
Cached中文解釋爲儲存。結合在一塊兒解釋儲存的線程池,說的更通俗易懂,既然要儲存,其容量確定是很大,因此他的corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE(2^32-1一個很大的數字)
(4)ScheduledThreadPool:
Scheduled中文解釋爲計劃。結合在一塊兒解釋計劃的線程池,顧名思義既然涉及到計劃,必然會涉及到時間。因此ScheduledThreadPool是一個具備定時按期執行任務功能的線程池。
什麼是單例呢?咳咳。
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種模式涉及到一個單一的類,該類負責建立本身的對象,同時確保只有單個對象被建立。這個類提供了一種訪問其惟一的對象的方式,能夠直接訪問,不須要實例化該類的對象。
注意事項:
推薦: http://www.runoob.com/design-...
二、線程池的單例
那麼問題來了,我線程池用的好好的,用的時候建立一個,不用就無論他,那爲何要將線程池設計成單例模式呢。那麼就要看看你將線程池應用的場所了。通常狀況下,整個系統中只須要單種線程池,多個線程公用一個線程池,不會是每創一個線程就要建立一個線程池,那樣子你還不如不用線程池呢。
言歸正傳,我們來看看如何將線程池設計成單例模式。廢話少說上代碼
首先在ThreadPool類裏面實現線程池的建立,咱們這裏建立的是FixedThreadPool線程池(記住構造方法要私有,保證不被其餘類實例化)
private ThreadPool(int corepoolsize, int maximumpoolsize, long keepalivetime) { this.corepoolsize = corepoolsize; this.maximumpoolsize = maximumpoolsize; this.keepalivetime = keepalivetime; } public void executor(Runnable runnable) { if (runnable == null) { return; } if (mexecutor == null) { mexecutor = new ThreadPoolExecutor(corepoolsize, //核心線程數 maximumpoolsize, //最大線程數 keepalivetime, //閒置線程存活時間 TimeUnit.MILLISECONDS, // 時間單位 new LinkedBlockingDeque<Runnable>(), //線程隊列 Executors.defaultThreadFactory(), //線程工廠 new ThreadPoolExecutor.AbortPolicy() //隊列已滿,並且當前線程數已經超過最大線程數時的異常處理策略 ); } mexecutor.execute(runnable); }
再而後對ThreadPool內部類,在類裏面對他實例化,實現單例
// 獲取單例的線程池對象 public static ThreadPool getThreadPool() { if (mThreadPool == null) { synchronized (ThreadManager.class) { if (mThreadPool == null) { int cpuNum = Runtime.getRuntime().availableProcessors();// 獲取處理器數量 int threadNum = cpuNum * 2 + 1;// 根據cpu數量,計算出合理的線程併發數 mThreadPool = new ThreadPool(threadNum, threadNum, 0L); } } } return mThreadPool; }