Java線程池

http://blog.csdn.net/evankaka/article/details/51489322

在線程池中執(zhí)行任務(wù)比為每個(gè)任務(wù)分配一個(gè)線程優(yōu)勢(shì)更多葱弟,通過重用現(xiàn)有的線程而不是創(chuàng)建新線程胚想,可以在處理多個(gè)請(qǐng)求時(shí)分?jǐn)偩€程創(chuàng)建和銷毀產(chǎn)生的巨大的開銷干茉。當(dāng)請(qǐng)求到達(dá)時(shí),通常工作線程已經(jīng)存在,提高了響應(yīng)性袋励;通過配置線程池的大小,可以創(chuàng)建足夠多的線程使CPU達(dá)到忙碌狀態(tài),還可以防止線程太多耗盡計(jì)算機(jī)的資源茬故。


一盖灸、Executors的API介紹

Java類庫提供了許多靜態(tài)方法來創(chuàng)建一個(gè)線程池:a、newFixedThreadPool 創(chuàng)建一個(gè)固定長(zhǎng)度的線程池磺芭,當(dāng)?shù)竭_(dá)線程最大數(shù)量時(shí)赁炎,線程池的規(guī)模將不再變化。 b钾腺、newCachedThreadPool 創(chuàng)建一個(gè)可緩存的線程池徙垫,如果當(dāng)前線程池的規(guī)模超出了處理需求,將回收空的線程垮庐;當(dāng)需求增加時(shí)松邪,會(huì)增加線程數(shù)量;線程池規(guī)模無限制哨查。 c逗抑、newSingleThreadPoolExecutor 創(chuàng)建一個(gè)單線程的Executor,確保任務(wù)對(duì)了寒亥,串行執(zhí)行 d邮府、newScheduledThreadPool 創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,而且以延遲或者定時(shí)的方式來執(zhí)行溉奕,類似Timer褂傀; 小結(jié)一下:在線程池中執(zhí)行任務(wù)比為每個(gè)任務(wù)分配一個(gè)線程優(yōu)勢(shì)更多,通過重用現(xiàn)有的線程而不是創(chuàng)建新線程加勤,可以在處理多個(gè)請(qǐng)求時(shí)分?jǐn)偩€程創(chuàng)建和銷毀產(chǎn)生的巨大的開銷仙辟。當(dāng)請(qǐng)求到達(dá)時(shí),通常工作線程已經(jīng)存在鳄梅,提高了響應(yīng)性叠国;通過配置線程池的大小,可以創(chuàng)建足夠多的線程使CPU達(dá)到忙碌狀態(tài)戴尸,還可以防止線程太多耗盡計(jì)算機(jī)的資源粟焊。

創(chuàng)建線程池基本方法:(1)定義線程類[java]?view plain?copyclass?Handler?implements?Runnable{??}??(2)建立ExecutorService線程池[java]?view plain?copyExecutorService?executorService?=?Executors.newCachedThreadPool();??或者 [java]?view plain?copyint?cpuNums?=?Runtime.getRuntime().availableProcessors();??//獲取當(dāng)前系統(tǒng)的CPU?數(shù)目??ExecutorService?executorService?=Executors.newFixedThreadPool(cpuNums?*?POOL_SIZE);?//ExecutorService通常根據(jù)系統(tǒng)資源情況靈活定義線程池大小??(3)調(diào)用線程池操作循環(huán)操作,成為daemon,把新實(shí)例放入Executor池中 [java]?view plain?copywhile(true){????executorService.execute(new?Handler(socket));????????//?class?Handler?implements?Runnable{????或者????executorService.execute(createTask(i));????????//private?static?Runnable?createTask(final?int?taskID)??}??execute(Runnable對(duì)象)方法其實(shí)就是對(duì)Runnable對(duì)象調(diào)用start()方法(當(dāng)然還有一些其他后臺(tái)動(dòng)作孙蒙,比如隊(duì)列项棠,優(yōu)先級(jí),IDLE timeout挎峦,active激活等)

二香追、幾種不同的ExecutorService線程池對(duì)象 1.newCachedThreadPool()?-緩存型池子,先查看池中有沒有以前建立的線程坦胶,如果有翅阵,就reuse.如果沒有歪玲,就建一個(gè)新的線程加入池中 -緩存型池子通常用于執(zhí)行一些生存期很短的異步型任務(wù) ?因此在一些面向連接的daemon型SERVER中用得不多。 -能reuse的線程掷匠,必須是timeout IDLE內(nèi)的池中線程,缺省timeout是60s,超過這個(gè)IDLE時(shí)長(zhǎng)岖圈,線程實(shí)例將被終止及移出池讹语。 ??注意,放入CachedThreadPool的線程不必?fù)?dān)心其結(jié)束蜂科,超過TIMEOUT不活動(dòng)顽决,其會(huì)自動(dòng)被終止。2.newFixedThreadPool-newFixedThreadPool與cacheThreadPool差不多导匣,也是能reuse就用才菠,但不能隨時(shí)建新的線程 -其獨(dú)特之處:任意時(shí)間點(diǎn),最多只能有固定數(shù)目的活動(dòng)線程存在贡定,此時(shí)如果有新的線程要建立赋访,只能放在另外的隊(duì)列中等待,直到當(dāng)前的線程中某個(gè)線程終止直接被移出池子 -和cacheThreadPool不同缓待,F(xiàn)ixedThreadPool沒有IDLE機(jī)制(可能也有蚓耽,但既然文檔沒提,肯定非常長(zhǎng)旋炒,類似依賴上層的TCP或UDP IDLE機(jī)制之類的)步悠,所以FixedThreadPool多數(shù)針對(duì)一些很穩(wěn)定很固定的正規(guī)并發(fā)線程,多用于服務(wù)器 -從方法的源代碼看瘫镇,cache池和fixed 池調(diào)用的是同一個(gè)底層池鼎兽,只不過參數(shù)不同: fixed池線程數(shù)固定,并且是0秒IDLE(無IDLE) cache池線程數(shù)支持0-Integer.MAX_VALUE(顯然完全沒考慮主機(jī)的資源承受能力)铣除,60秒IDLE??3.ScheduledThreadPool-調(diào)度型線程池 -這個(gè)池子里的線程可以按schedule依次delay執(zhí)行谚咬,或周期執(zhí)行4.SingleThreadExecutor-單例線程,任意時(shí)間池中只能有一個(gè)線程 -用的是和cache池和fixed池相同的底層池通孽,但線程數(shù)目是1-1,0秒IDLE(無IDLE)?



應(yīng)用實(shí)例:

1.CachedThreadPoolCachedThreadPool首先會(huì)按照需要?jiǎng)?chuàng)建足夠多的線程來執(zhí)行任務(wù)(Task)序宦。隨著程序執(zhí)行的過程,有的線程執(zhí)行完了任務(wù)背苦,可以被重新循環(huán)使用時(shí)互捌,才不再創(chuàng)建新的線程來執(zhí)行任務(wù)。我們采用《Thinking In Java》中的例子來分析行剂★踉耄客戶端線程和線程池之間會(huì)有一個(gè)任務(wù)隊(duì)列。當(dāng)程序要關(guān)閉時(shí)厚宰,你需要注意兩件事情:入隊(duì)的這些任務(wù)的情況怎么樣了以及正在運(yùn)行的這個(gè)任務(wù)執(zhí)行得如 何了腌巾。令人驚訝的是很多開發(fā)人員并沒能正確地或者有意識(shí)地去關(guān)閉線程池遂填。正確的方法有兩種:一個(gè)是讓所有的入隊(duì)任務(wù)都執(zhí)行完畢(shutdown()), 再就是舍棄這些任務(wù)(shutdownNow())——這完全取決于你澈蝙。比如說如果我們提交了N多任務(wù)并且希望等它們都執(zhí)行完后才返回的話吓坚,那么就使用 shutdown():

2.FixedThreadPool?

FixedThreadPool模式會(huì)使用一個(gè)優(yōu)先固定數(shù)目的線程來處理若干數(shù)目的任務(wù)。規(guī)定數(shù)目的線程處理所有任務(wù)灯荧,一旦有線程處理完了任務(wù)就會(huì)被用來處理新的任務(wù)(如果有的話)礁击。這種模式與上面的CachedThreadPool是不同的,CachedThreadPool模式下處理一定數(shù)量的任務(wù)的線程數(shù)目是不確定的逗载。而FixedThreadPool模式下最多 的線程數(shù)目是一定的哆窿。

3、newSingleThreadExecutor其實(shí)這個(gè)就是創(chuàng)建只能運(yùn)行一條線程的線程池厉斟。它能保證線程的先后順序執(zhí)行挚躯,并且能保證一條線程執(zhí)行完成后才開啟另一條新的線程

4、newScheduledThreadPool這是一個(gè)計(jì)劃線程池類擦秽,它能設(shè)置線程執(zhí)行的先后間隔及執(zhí)行時(shí)間等码荔,功能比上面的三個(gè)強(qiáng)大了一些。

ScheduledThreadPoolExecutor的定時(shí)方法主要有以下四種: 下面將主要來具體講講scheduleAtFixedRate和scheduleWithFixedDelayscheduleAtFixedRate?按指定頻率周期執(zhí)行某個(gè)任務(wù) public ScheduledFuture scheduleAtFixedRate(Runnable command,? long initialDelay,? long period,? TimeUnit unit);? command:執(zhí)行線程 initialDelay:初始化延時(shí) period:兩次開始執(zhí)行最小間隔時(shí)間 unit:計(jì)時(shí)單位 scheduleWithFixedDelay?周期定時(shí)執(zhí)行某個(gè)任務(wù)/按指定頻率間隔執(zhí)行某個(gè)任務(wù)(注意) public ScheduledFuture scheduleWithFixedDelay(Runnable command,? long initialDelay,? long delay,? TimeUnit unit);? command:執(zhí)行線程 initialDelay:初始化延時(shí) period:前一次執(zhí)行結(jié)束到下一次執(zhí)行開始的間隔時(shí)間(間隔執(zhí)行延遲時(shí)間) unit:計(jì)時(shí)單位

1.按指定頻率周期執(zhí)行某個(gè)任務(wù) 下面實(shí)現(xiàn)每隔2秒執(zhí)行一次号涯,注意目胡,如果上次的線程還沒有執(zhí)行完成,那么會(huì)阻塞下一個(gè)線程的執(zhí)行链快。即使線程池設(shè)置得足夠大誉己。

/**??

*?初始化延遲0ms開始執(zhí)行,每隔2000ms重新執(zhí)行一次任務(wù)??

*?@author?linbingwen?

?*?@since??2016年6月6日??

*/??

public?static?void?executeFixedRate()?{

????????ScheduledExecutorService?executor?=?Executors.newScheduledThreadPool(10);???????

?executor.scheduleAtFixedRate(new?MyHandle(),0,2000域蜗, TimeUnit.MILLISECONDS);????}????

間隔指的是連續(xù)兩次任務(wù)開始執(zhí)行的間隔巨双。對(duì)于scheduleAtFixedRate方法,當(dāng)執(zhí)行任務(wù)的時(shí)間大于我們指定的間隔時(shí)間時(shí)霉祸,它并不會(huì)在指定間隔時(shí)開辟一個(gè)新的線程并發(fā)執(zhí)行這個(gè)任務(wù)筑累。而是等待該線程執(zhí)行完畢。

2丝蹭、按指定頻率間隔執(zhí)行某個(gè)任務(wù)

/**?

?* 以固定延遲時(shí)間進(jìn)行執(zhí)行?

?* 本次任務(wù)執(zhí)行完成后慢宗,需要延遲設(shè)定的延遲時(shí)間,才會(huì)執(zhí)行新的任務(wù)?

?*/

?public static void executeFixedDelay() {?

?ScheduledExecutorService executor = Executors.newScheduledThreadPool(10); executor.scheduleWithFixedDelay( new MyHandle(), 0, 2000, TimeUnit.MILLISECONDS);?

?}

間隔指的是連續(xù)上次執(zhí)行完成和下次開始執(zhí)行之間的間隔奔穿。

3.周期定時(shí)執(zhí)行某個(gè)任務(wù) 周期性的執(zhí)行一個(gè)任務(wù)镜沽,可以使用下面方法設(shè)定每天在固定時(shí)間執(zhí)行一次任務(wù)。

/**

?* 每天晚上9點(diǎn)執(zhí)行一次

?* 每天定時(shí)安排任務(wù)進(jìn)行執(zhí)行?

*/?

public static void executeEightAtNightPerDay() {?

?ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); long oneDay = 24 * 60 * 60 * 1000;?

?long initDelay = getTimeMillis("21:00:00") - System.currentTimeMillis();?

?initDelay = initDelay > 0 ? initDelay : oneDay + initDelay; executor.scheduleAtFixedRate( new MyThread(), initDelay, oneDay, TimeUnit.MILLISECONDS); }

?/**?

?* 獲取指定時(shí)間對(duì)應(yīng)的毫秒數(shù)?

?* @param time "HH:mm:ss"

?* @return?

?*/?

private static long getTimeMillis(String time) {?

?try { DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");

?Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time); return curDate.getTime();?

?} catch (ParseException e) {

?e.printStackTrace();

?}?

?return 0;

?}

3贱田、shutdown()通常放在execute后面缅茉。如果調(diào)用 了這個(gè)方法,一方面男摧,表明當(dāng)前線程池已不再接收新添加的線程蔬墩,新添加的線程會(huì)被拒絕執(zhí)行译打。另一方面,表明當(dāng)所有線程執(zhí)行完畢時(shí)拇颅,回收線程池的資源奏司。注意,它不會(huì)馬上關(guān)閉線程池蔬蕊!

4结澄、shutdownNow()不管當(dāng)前有沒有線程在執(zhí)行,馬上關(guān)閉線程池岸夯!這個(gè)方法要小心使用,要不可能會(huì)引起系統(tǒng)數(shù)據(jù)異常们妥!

總結(jié):? ? ? ?ThreadPoolExecutor中猜扮,包含了一個(gè)任務(wù)緩存隊(duì)列和若干個(gè)執(zhí)行線程,任務(wù)緩存隊(duì)列是一個(gè)大小固定的緩沖區(qū)隊(duì)列监婶,用來緩存待執(zhí)行的任務(wù)旅赢,執(zhí)行線程用來處理待執(zhí)行的任務(wù)。每個(gè)待執(zhí)行的任務(wù)惑惶,都必須實(shí)現(xiàn)Runnable接口煮盼,執(zhí)行線程調(diào)用其run()方法,完成相應(yīng)任務(wù)带污。 ThreadPoolExecutor對(duì)象初始化時(shí)僵控,不創(chuàng)建任何執(zhí)行線程,當(dāng)有新任務(wù)進(jìn)來時(shí)鱼冀,才會(huì)創(chuàng)建執(zhí)行線程报破。

構(gòu)造ThreadPoolExecutor對(duì)象時(shí),需要配置該對(duì)象的核心線程池大小和最大線程池大星鳌: 當(dāng)目前執(zhí)行線程的總數(shù)小于核心線程大小時(shí)充易,所有新加入的任務(wù),都在新線程中處理 當(dāng)目前執(zhí)行線程的總數(shù)大于或等于核心線程時(shí)荸型,所有新加入的任務(wù)盹靴,都放入任務(wù)緩存隊(duì)列中 當(dāng)目前執(zhí)行線程的總數(shù)大于或等于核心線程,并且緩存隊(duì)列已滿瑞妇,同時(shí)此時(shí)線程總數(shù)小于線程池的最大大小稿静,那么創(chuàng)建新線程,加入線程池中踪宠,協(xié)助處理新的任務(wù)自赔。 當(dāng)所有線程都在執(zhí)行,線程池大小已經(jīng)達(dá)到上限柳琢,并且緩存隊(duì)列已滿時(shí)绍妨,就rejectHandler拒絕新的任務(wù)

五润脸、自定義線程池再來看看它的方法[java]?view plain?copypublic?ThreadPoolExecutor(int?corePoolSize,//核心線程大小????????????????????????????

int?maximumPoolSize,//最大線程大小?????????????????????????????

long?keepAliveTime,//線程緩存時(shí)間????????????????????????????

TimeUnit?unit,//前面keepAlive????????????????????????????

BlockingQueue?workQueue,//緩存隊(duì)列????????????????????????????

ThreadFactory?threadFactory,//線程工大????????????????????????????

RejectedExecutionHandler?handler)//拒絕策略??














































































最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市他去,隨后出現(xiàn)的幾起案子毙驯,更是在濱河造成了極大的恐慌,老刑警劉巖灾测,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爆价,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡媳搪,警方通過查閱死者的電腦和手機(jī)铭段,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秦爆,“玉大人序愚,你說我怎么就攤上這事〉认蓿” “怎么了爸吮?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)望门。 經(jīng)常有香客問我形娇,道長(zhǎng),這世上最難降的妖魔是什么筹误? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任桐早,我火速辦了婚禮,結(jié)果婚禮上纫事,老公的妹妹穿的比我還像新娘勘畔。我一直安慰自己,他們只是感情好丽惶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布炫七。 她就那樣靜靜地躺著,像睡著了一般钾唬。 火紅的嫁衣襯著肌膚如雪万哪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天抡秆,我揣著相機(jī)與錄音奕巍,去河邊找鬼。 笑死儒士,一個(gè)胖子當(dāng)著我的面吹牛的止,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播着撩,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼诅福,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼匾委!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起氓润,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤赂乐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后咖气,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挨措,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年崩溪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浅役。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伶唯,死狀恐怖担租,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抵怎,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布岭参,位于F島的核電站反惕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏演侯。R本人自食惡果不足惜姿染,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秒际。 院中可真熱鬧悬赏,春花似錦、人聲如沸娄徊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寄锐。三九已至兵多,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橄仆,已是汗流浹背剩膘。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盆顾,地道東北人怠褐。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像您宪,于是被迫代替她去往敵國和親奈懒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子奠涌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容