本文主要有以下三部分內(nèi)容:
第一部分:多線程有什么用迄靠?
第二部分:線程池有什么用?
第三部分:線程池相關(guān)好文章
多線程有什么用轿腺?
(1)發(fā)揮多核CPU的優(yōu)勢(shì):筆記本锦聊、臺(tái)式機(jī)乃至商用的應(yīng)用服務(wù)器至少也都是雙核的,4核、8核甚至16核的也都不少見截碴,如果是單線程的程序梳侨,那么在雙核CPU上就浪費(fèi)了50%,在4核CPU上就浪費(fèi)了75%日丹。單核CPU上所謂的”多線程”那是假的多線程走哺,同一時(shí)間處理器只會(huì)處理一段邏輯,只不過線程之間切換得比較快哲虾,看著像多個(gè)線程”同時(shí)”運(yùn)行罷了丙躏。多核CPU上的多線程才是真正的多線程,它能讓你的多段邏輯同時(shí)工作束凑,多線程晒旅,可以真正發(fā)揮出多核CPU的優(yōu)勢(shì)來,達(dá)到充分利用CPU的目的汪诉。
(2)防止阻塞:從程序運(yùn)行效率的角度來看废恋,單核CPU不但不會(huì)發(fā)揮出多線程的優(yōu)勢(shì),反而會(huì)因?yàn)樵趩魏薈PU上運(yùn)行多線程導(dǎo)致線程上下文的切換扒寄,而降低程序整體的效率鱼鼓。但是單核CPU我們還是要應(yīng)用多線程,就是為了防止阻塞该编。試想迄本,如果單核CPU使用單線程,那么只要這個(gè)線程阻塞了课竣,比方說遠(yuǎn)程讀取某個(gè)數(shù)據(jù)吧嘉赎,對(duì)端遲遲未返回又沒有設(shè)置超時(shí)時(shí)間,那么你的整個(gè)程序在數(shù)據(jù)返回回來之前就停止運(yùn)行了稠氮。多線程可以防止這個(gè)問題曹阔,多條線程同時(shí)運(yùn)行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞隔披,也不會(huì)影響其它任務(wù)的執(zhí)行赃份。
線程池有什么用?
在java中奢米,如果每個(gè)請(qǐng)求到達(dá)就創(chuàng)建一個(gè)新線程抓韩,開銷是相當(dāng)大的。在實(shí)際使用中鬓长,服務(wù)器在創(chuàng)建和銷毀線程上花費(fèi)的時(shí)間和消耗的系統(tǒng)資源都相當(dāng)大谒拴,甚至可能要比在處理實(shí)際的用戶請(qǐng)求的時(shí)間和資源要多的多。除了創(chuàng)建和銷毀線程的開銷之外涉波,活動(dòng)的線程也需要消耗系統(tǒng)資源英上。如果在一個(gè)jvm里創(chuàng)建太多的線程炭序,可能會(huì)使系統(tǒng)由于過度消耗內(nèi)存或“切換過度”而導(dǎo)致系統(tǒng)資源不足。為了防止資源不足苍日,服務(wù)器應(yīng)用程序需要采取一些辦法來限制任何給定時(shí)刻處理的請(qǐng)求數(shù)目惭聂,盡可能減少創(chuàng)建和銷毀線程的次數(shù),特別是一些資源耗費(fèi)比較大的線程的創(chuàng)建和銷毀相恃,盡量利用已有對(duì)象來進(jìn)行服務(wù)辜纲,線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對(duì)多個(gè)任務(wù)重復(fù)使用線程拦耐,線程創(chuàng)建的開銷就被分?jǐn)偟搅硕鄠€(gè)任務(wù)上了耕腾,
而且由于在請(qǐng)求到達(dá)時(shí)線程已經(jīng)存在,所以消除了線程創(chuàng)建所帶來的延遲杀糯。這樣扫俺,就可以立即為請(qǐng)求服務(wù),使用應(yīng)用程序響應(yīng)更快火脉。另外牵舵,通過適當(dāng)?shù)恼{(diào)整線程中的線程數(shù)目可以防止出現(xiàn)資源不足的情況柒啤。
舉例說明:
假如一個(gè)服務(wù)器完成一項(xiàng)任務(wù)的時(shí)間為T:
T1 創(chuàng)建線程的時(shí)間
T2 在線程中執(zhí)行任務(wù)的時(shí)間倦挂,包括線程同步所需要的時(shí)間
T3 線程銷毀的時(shí)間
顯然 T= T1+T2+T3. 注意:這是一個(gè)理想化的情況。
可以看出担巩,T1方援,T3是多線程自身帶來的開銷(在Java中,通過映射pThread涛癌,并進(jìn)一步通過SystemCall實(shí)現(xiàn)native線程)犯戏,我們渴望減少T1和T3的時(shí)間,從而減少T的時(shí)間拳话。但是一些線程的使用者并沒有注意到這一點(diǎn)先匪,所以在線程中頻繁的創(chuàng)建或者銷毀線程,這導(dǎo)致T1和T3在T中占有相當(dāng)比例弃衍。這顯然突出的線程池的弱點(diǎn)(T1呀非,T3),而不是有點(diǎn)(并發(fā)性)。所以線程池的技術(shù)正是如何關(guān)注縮短或調(diào)整T1镜盯,T3時(shí)間的技術(shù)岸裙,從而提高服務(wù)器程序的性能。
線程池技術(shù)關(guān)注的問題:
1速缆、通過對(duì)線程進(jìn)行緩存降允,減少創(chuàng)建和銷毀時(shí)間的損失
2、通過控制線程數(shù)量的閥值艺糜,減少線程過少帶來的CPU閑置(比如長時(shí)間卡在I/O上了)與線程過多給JVM內(nèi)存與線程切換時(shí)系統(tǒng)調(diào)用的壓力剧董。
其實(shí)線程池技術(shù)主要是減少線程創(chuàng)建幢尚、切換、銷毀所占用時(shí)間翅楼,其中線程創(chuàng)建和銷毀我們可以控制侠草,線程切換主要是CPU來完成,我們能做到的就是減少線程創(chuàng)建和銷毀帶來的開銷犁嗅。
線程池相關(guān)好文章
Java并發(fā)編程:線程池的使用
本文是我見過對(duì)線程池講解最好的文章边涕,前兩年看過一次保存了下來,昨天又看了一次感覺還是經(jīng)典中的經(jīng)典褂微,Java并發(fā)編程:線程池的使用看完以后基本就掌握了線程池相關(guān)內(nèi)容功蜓。
主要內(nèi)容有:
一.Java中的ThreadPoolExecutor類
介紹相關(guān)參數(shù)、方法以及類之間的關(guān)系宠蚂。
二.深入剖析線程池實(shí)現(xiàn)原理
這部分內(nèi)容最重要式撼,也是理解線程池的核心內(nèi)容,主要內(nèi)容有:
1.線程池狀態(tài):介紹線程池相關(guān)狀態(tài)求厕。
2.任務(wù)的執(zhí)行:對(duì)任務(wù)提交給線程池之后到被執(zhí)行的整個(gè)過程進(jìn)行了講解(理解線程池核心中的核心)著隆。
3.線程池中的線程初始化
4.任務(wù)緩存隊(duì)列及排隊(duì)策略
1)ArrayBlockingQueue:基于數(shù)組的先進(jìn)先出隊(duì)列,此隊(duì)列創(chuàng)建時(shí)必須指定大醒窖ⅰ美浦;
2)LinkedBlockingQueue:基于鏈表的先進(jìn)先出隊(duì)列,如果創(chuàng)建時(shí)沒有指定此隊(duì)列大小项栏,則默認(rèn)為Integer.MAX_VALUE浦辨;
3)synchronousQueue:這個(gè)隊(duì)列比較特殊,它不會(huì)保存提交的任務(wù)沼沈,而是將直接新建一個(gè)線程來執(zhí)行新來的任務(wù)流酬。
5.任務(wù)拒絕策略
1)ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
2)ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù)列另,但是不拋出異常芽腾。
3)ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
4)ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
6.線程池的關(guān)閉:shutdown()和shutdownNow()來關(guān)閉線程池页衙。
7.線程池容量的動(dòng)態(tài)調(diào)整:setCorePoolSize()和setMaximumPoolSize()可動(dòng)態(tài)調(diào)整線程池容量大小摊滔。
三.使用示例
通過具體例子,展示線程池緩存拷姿、排隊(duì)惭载、拒絕策略,自己也可以寫一些例子來驗(yàn)證線程池相關(guān)原理响巢。
四.如何合理配置線程池的大小
如何合理配置線程池大小提供一些參考描滔。
以上是Java并發(fā)編程:線程池的使用主要內(nèi)容介紹,也算是自己對(duì)文章內(nèi)容的簡單總結(jié)踪古,建議直接閱讀原文含长,并參考源碼學(xué)習(xí)線程池券腔。