接深入淺出多線程系列4,
線程對(duì)象的創(chuàng)建和銷毀是需要花費(fèi)系統(tǒng)資源的,通過(guò)線程池,可以避免該問題并提高系統(tǒng)的響應(yīng)時(shí)間。這種情形類似我們常提到的數(shù)據(jù)庫(kù)連接池。
線程池的廣泛應(yīng)用使得在SUN在JDK 1.5的工具包提供了線程池的支持。我計(jì)劃將該系列分為設(shè)計(jì)需求與設(shè)計(jì)實(shí)現(xiàn)兩個(gè)部分。這樣會(huì)更加清晰。如果想要熟悉,并熟練應(yīng)用線程池,那么通過(guò)設(shè)計(jì)需求篇也就是該篇就可以找到答案。如果想探究實(shí)現(xiàn)的細(xì)節(jié),那么在設(shè)計(jì)實(shí)現(xiàn)篇會(huì)有深入的說(shuō)明。
本文以Concurrent包線程池設(shè)計(jì)為例,討論線程池的設(shè)計(jì)。
- 線程池需求
設(shè)計(jì)與實(shí)現(xiàn)的最終目標(biāo)是滿足需求,這是軟件開發(fā)的基本原則。我們先考慮考慮對(duì)線程池的需求。作為一名開發(fā)人員,我們最主要的需求就是線程池簡(jiǎn)單,易用。即使你的設(shè)計(jì)算法多么優(yōu)雅,但給使用者復(fù)雜的使用步驟也是得不償失,簡(jiǎn)單就是美!最好我們不用深究你的具體實(shí)現(xiàn),通過(guò)簡(jiǎn)單的接口就可以應(yīng)用。其次就是技術(shù)角度,線程池的設(shè)計(jì)應(yīng)該是比較柔性的,提供很好的可配置可管理與可擴(kuò)張性。
對(duì)于可配置可管理的需求,至少的提供以下的功能點(diǎn):
- 線程池里,線程數(shù)量的配置。
- 能夠提供動(dòng)態(tài)調(diào)整線程的數(shù)量。
- 能夠Shutdown 最好能夠提供優(yōu)雅的Shundown,而不是像我們通過(guò)切斷電源關(guān)閉機(jī)器那樣粗暴的Shutdown。
- 能夠提供Task的狀態(tài),比如完成了多少,還有多少?zèng)]有完成。
對(duì)于可擴(kuò)展性而言有以下幾點(diǎn):
- 如果不能滿足需要能夠很容易的擴(kuò)展。
- 對(duì)于線程池線程的創(chuàng)建能否提夠擴(kuò)展。
- 當(dāng)提交的Task負(fù)載過(guò)大時(shí),線程池的處理策略能否擴(kuò)展。
以上是對(duì)線程池的需求的討論。
2.上面就這些對(duì)于我們使用者而言,對(duì)線程池的需求,下面我們分析Concurrent包提供的線程池是否達(dá)到了我們的需求。
對(duì)于易用的需求。
Concurrent的Executors類,注意不是Executor接口,通過(guò)Factory模式提供了我們以下的基本的線程池,如果沒有
特殊的需求,只需查閱這幾個(gè)線程池JDK文檔,就可以使用了。
- newFixedThreadPool 顧名思義,建立固定大小的線程池。
- newCachedThreadPool 根據(jù)需要?jiǎng)討B(tài)的創(chuàng)建線程,該線程池我們?cè)谏钊胂盗?做了討論。
- newSingleThreadExecutor 如其名。
- newScheduledThreadPool 如其名,該線程池類似于JDK1.4 Timer提供的功能,但更完善,我會(huì)在隨后的深入淺出系列討論其不同 點(diǎn)。
總之,從易用性的角度見,Concurrent包提供的接口是不錯(cuò)的。
對(duì)于可配置,可管理講:
- 提供了可以配置線程池中線程的數(shù)量的功能。比如在創(chuàng)建newFixedThreadPool時(shí),第一個(gè)參數(shù)就是線程池線程的數(shù)量,通過(guò)
- 該數(shù)量的配置,我們就可以保證不會(huì)因?yàn)榫€程的過(guò)多導(dǎo)致系統(tǒng)的崩潰。
- 提供了在運(yùn)行時(shí)通過(guò)setCorePoolSize和setMaximumPoolSize方法來(lái)調(diào)整線程池?cái)?shù)量的功能,兩者的區(qū)別會(huì)在后續(xù)實(shí)現(xiàn)篇中說(shuō)明。
- 提夠了優(yōu)雅的Shutdown,不在接受Task,將正在運(yùn)行的Task執(zhí)行完,處于等待狀態(tài)的Task 中斷。
- 提供getTaskCount和getCompletedTaskCount方法可以獲取提交的Task和完成的Task數(shù)量。
對(duì)于可擴(kuò)展性
- 我們可以參考Executors的Factory模式,擴(kuò)展提供滿足需要的線程池。
- 在構(gòu)造方法中,提供ThreadFactory接口,我們可以實(shí)現(xiàn)自定義的創(chuàng)建線程池線程的方法。
- 提供了RejectedExecutionHandler接口,我們可以擴(kuò)張?jiān)摻涌冢峁┊?dāng)Task過(guò)多時(shí),處理策略,目前默認(rèn)為AbortPolicy策略Throw 一個(gè)RejectedExecutionException
總之,Concurrent中Executors類通過(guò)Factory Method方法,提供了基本常用的線程池。 Executors 其實(shí)通過(guò)線程池實(shí)現(xiàn)類-ThreadPoolExecutor創(chuàng)建基本的線程池,所以我們可以通過(guò)ThreadPoolExecutor提供的API來(lái)配置擴(kuò)展來(lái)實(shí)現(xiàn)個(gè)性化需求的線程池。