线程池的好处,详解,单例(绝对好记)
??????轉載請注意出處:http://blog.csdn.net/fengye454545/article/details/79536986
??????前幾天公司面試,問了很多線程池的問題,由于也是菜鳥一只本來對線程池就不太熟悉,再加上一緊張腦袋一緊,就GG了,之后可謂是深惡痛極,決定把線程池這邊好好的整理一番。
一、線程池的好處
????????線程池是啥子,干啥使它呀,老子線程使得好好的,非得多次一舉,哈哈,想必來這里看這篇文章的都對線程池有點了解。那么我來整理整理線程池的好處吧。
1、線程池的重用
????????線程的創建和銷毀的開銷是巨大的,而通過線程池的重用大大減少了這些不必要的開銷,當然既然少了這么多消費內存的開銷,其線程執行速度也是突飛猛進的提升。
2、控制線程池的并發數
???????初學新手可能對并發這個詞語比較陌生,特此我也是結合百度百科和必生所學得出最優解釋,萬萬記著并發可跟并行不一樣。
并發:在某個時間段內,多個程序都處在執行和執行完畢之間;但在一個時間點上只有一個程序在運行。頭腦風暴:老鷹媽媽喂小雛鷹食物,小雛鷹很多,而老鷹只有一張嘴,她需要一個個喂過去,到最后每個小雛鷹都可以吃到,但是在一個時間點里只能有一個小雛鷹可以吃到美味的食物。
并行:在某個時間段里,每個程序按照自己獨立異步的速度執行,程序之間互不干擾。頭腦風暴:這就好似老鷹媽媽決定這樣喂食太費勁于是為每個小雛鷹請了個保姆,這樣子在一個時間點里,每個小雛鷹都可以同時吃到食物,而且互相不干擾。
????????回到線程池,控制線程池的并發數可以有效的避免大量的線程池爭奪CPU資源而造成堵塞。頭腦風暴:還是拿老鷹的例子來講,媽媽只有一個,要這么一個個喂下去,一些餓壞的小雛鷹等不下去了就要破壞規則,搶在靠前喂食的雛鷹面前,而前面的雛鷹也不是吃軟飯的,于是打起來了,場面混亂。老鷹生氣了,這么不懂事,誰也別吃了,于是造成了最后誰也沒食吃的局面。
3、線程池可以對線程進行管理
????????線程池可以提供定時、定期、單線程、并發數控制等功能。比如通過ScheduledThreadPool線程池來執行S秒后,每隔N秒執行一次的任務。
二、線程池的詳解
推薦博客:http://blog.csdn.net/seu_calvin/article/details/52415337
想必看完上面那篇博客,大家可謂贊不絕口,不過可能有些小伙伴還是記不下來,還有些小伙伴覺得好惡心呀,怎么都是廁所啥的呀!哈哈別著急,我來給大家一種好記的辦法。
先來講講參數最多的那個構造方法,主要是對那幾個煩人的參數進行分析。
1、ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)這里是7個參數(我們在開發中用的更多的是5個參數的構造方法),OK,那我們來看看這里七個參數的含義:
corePoolSize? 線程池中核心線程的數量
maximumPoolSize? 線程池中最大線程數量
keepAliveTime?非核心線程的超時時長,當系統中非核心線程閑置時間超過keepAliveTime之后,則會被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置為true,則該參數也表示核心線程的超時時長
unit?第三個參數的單位,有納秒、微秒、毫秒、秒、分、時、天等
workQueue?線程池中的任務隊列,該隊列主要用來存儲已經被提交但是尚未執行的任務。存儲在這里的任務是由ThreadPoolExecutor的execute方法提交來的。
threadFactory? 為線程池提供創建新線程的功能,這個我們一般使用默認即可
handler?拒絕策略,當線程無法執行新任務時(一般是由于線程池中的線程數量已經達到最大數或者線程池關閉導致的),默認情況下,當線程池無法處理新線程時,會拋出一個RejectedExecutionException。
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(燒烤店室內座位),cuurentPoolSize(目前到燒烤店的顧客數量),maximumPoolSize(燒烤店室內+室外+侯廳室所有座位),workQueue(燒烤店為顧客專門設置的侯廳室)
第(1)種,燒烤店人數不多的時候,室內位置很多,大家都其樂融融,開心的坐在室內吃著燒烤,看著世界杯。
第(2)種,生意不錯,室內燒烤店坐無空席,大家都不愿意去外面吃,于是在侯廳室里呆著,侯廳室位置沒坐滿。
第(3)種,生意興隆,室內、侯廳室都坐無空席,但是顧客太餓了,剩下的人沒辦法只好淋著雨吃燒烤,哈哈,好可憐。
第(4)種,生意爆棚,室內、室外、侯廳室都坐無空席,在有顧客過來直接趕走。
哈哈是不是很形象,對于workQueue還是有點陌生的小伙伴。
推薦博客:http://blog.csdn.net/u012702547/article/details/52259529
2、其他線程池的記法
剩下的那四種主要的線程池大概思路,用法在我推薦的博客里都有詳細解說,在這里我就不一一道來了,在這里主要是跟大家分享一種特別容易記住這四種線程池的方法,在大家寫代碼,面試時可以即使想到這四種線程池。
(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是一個具有定時定期執行任務功能的線程池。
三、線程池的單例
容我伸個懶腰,該講本章重點內容了,在此之前,我們對基本語意知識進行了解一下。
什么是單例呢?咳咳。
1、單例
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
注意事項:
- 1、單例類只能有一個實例。
- 2、單例類必須自己創建自己的唯一實例。
- 3、單例類必須給所有其他對象提供這一實例。
推薦:http://www.runoob.com/design-pattern/singleton-pattern.html
2、線程池的單例
那么問題來了,我線程池用的好好的,用的時候創建一個,不用就不管他,那為什么要將線程池設計成單例模式呢。那么就要看看你將線程池應用的場所了。一般情況下,整個系統中只需要單種線程池,多個線程公用一個線程池,不會是每創一個線程就要創建一個線程池,那樣子你還不如不用線程池呢。
言歸正傳,咱們來看看如何將線程池設計成單例模式。廢話少說上代碼
首先在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;}Demo地址:https://download.csdn.net/download/fengye454545/10284814
菜鳥一只,如有不對之處請指出。您的鼓勵是我寫作的最大動力!
總結
以上是生活随笔為你收集整理的线程池的好处,详解,单例(绝对好记)的全部內容,希望文章能夠幫你解決所遇到的問題。