Executor框架最核心的類是ThreadPoolExecutor,它是線程池的實現(xiàn)類再愈,主要由下列4個組件構(gòu)成缰泡。
????·corePool:核心線程池的大小。
????·maximumPool:最大線程池的大小明肮。
????·BlockingQueue:用來暫時保存任務(wù)的工作隊列。
????·RejectedExecutionHandler:當(dāng)ThreadPoolExecutor已經(jīng)關(guān)閉或ThreadPoolExecutor已經(jīng)飽和時(達到了最大線程池大小且工作隊列已滿)缭付,execute()方法將要調(diào)用的Handler柿估。
通過Executor框架的工具類Executors,可以創(chuàng)建3種類型的ThreadPoolExecutor陷猫。
????·FixedThreadPool秫舌。
????·SingleThreadExecutor。
????·CachedThreadPool烙丛。?
下面將分別介紹這3種ThreadPoolExecutor。
FixedThreadPool被稱為可重用固定線程數(shù)的線程池羔味。下面是FixedThreadPool的源代碼實現(xiàn)河咽。
public?static?ExecutorService?newFixedThreadPool(int?nThreads)?{?
????return?new?ThreadPoolExecutor(nThreads,nThreads,
????0L,?TimeUnit.MILLISECONDS,new?LinkedBlockingQueue());
}
FixedThreadPool的corePoolSize和maximumPoolSize都被設(shè)置為創(chuàng)建FixedThreadPool時指定的參數(shù)nThreads。當(dāng)線程池中的線程數(shù)大于corePoolSize時赋元,keepAliveTime為多余的空閑線程等待新任務(wù)的最長時間忘蟹,超過這個時間后多余的線程將被終止。這里把keepAliveTime設(shè)置為0L搁凸,意味著多余的空閑線程會被立即終止媚值。
FixedThreadPool的execute()方法的運行示意圖如圖所示。
上圖的說明如下护糖。
????1)如果當(dāng)前運行的線程數(shù)少于corePoolSize褥芒,則創(chuàng)建新線程來執(zhí)行任務(wù)。
????2)在線程池完成預(yù)熱之后(當(dāng)前運行的線程數(shù)等于corePoolSize)嫡良,將任務(wù)加入?LinkedBlockingQueue锰扶。
????3)線程執(zhí)行完1中的任務(wù)后,會在循環(huán)中反復(fù)從LinkedBlockingQueue獲取任務(wù)來執(zhí)行寝受。
FixedThreadPool使用無界隊列LinkedBlockingQueue作為線程池的工作隊列(隊列的容量為?Integer.MAX_VALUE)坷牛。使用無界隊列作為工作隊列會對線程池帶來如下影響。
????1)當(dāng)線程池中的線程數(shù)達到corePoolSize后很澄,新任務(wù)將在無界隊列中等待京闰,因此線程池中的線程數(shù)不會超過? ?????corePoolSize颜及。
????2)由于1,使用無界隊列時maximumPoolSize將是一個無效參數(shù)蹂楣。?
????3)由于1和2俏站,使用無界隊列時keepAliveTime將是一個無效參數(shù)。
????4)由于使用無界隊列乾翔,運行中的FixedThreadPool(未執(zhí)行方法shutdown()或?shutdownNow())不會拒絕任務(wù)? ?(不會調(diào)用RejectedExecutionHandler.rejectedExecution方法)。
SingleThreadExecutor詳解
SingleThreadExecutor是使用單個worker線程的Executor施戴。下面是SingleThreadExecutor的源代碼實現(xiàn)。
public?static?ExecutorService?newSingleThreadExecutor()?{?
????return?new?FinalizableDelegatedExecutorService(new?ThreadPoolExecutor(1,?1,0L,?TimeUnit.MILLISECONDS????,new?LinkedBlockingQueue()));
}
SingleThreadExecutor的corePoolSize和maximumPoolSize被設(shè)置為1赞哗。其他參數(shù)與?FixedThreadPool相同。SingleThreadExecutor使用無界隊列LinkedBlockingQueue作為線程池的工作隊列(隊列的容量為Integer.MAX_VALUE)肪笋。SingleThreadExecutor使用無界隊列作為工作隊列對線程池帶來的影響與FixedThreadPool相同月劈,這里就不贅述了。
SingleThreadExecutor的運行示意圖如圖所示藤乙。
對上圖的說明如下猜揪。
????1)如果當(dāng)前運行的線程數(shù)少于corePoolSize(即線程池中無運行的線程)坛梁,則創(chuàng)建一個新線程來執(zhí)行任務(wù)而姐。
????2)在線程池完成預(yù)熱之后(當(dāng)前線程池中有一個運行的線程)划咐,將任務(wù)加入Linked-?BlockingQueue拴念。
????3)線程執(zhí)行完1中的任務(wù)后,會在一個無限循環(huán)中反復(fù)從LinkedBlockingQueue獲取任務(wù)來執(zhí)行褐缠。
CachedThreadPool詳解
CachedThreadPool是一個會根據(jù)需要創(chuàng)建新線程的線程池政鼠。下面是創(chuàng)建CachedThreadPool的源代碼。
public?static?ExecutorService?newCachedThreadPool()?{ ????return?new?ThreadPoolExecutor(0,?Integer.MAX_VALUE,
????60L,?TimeUnit.SECONDS,new?SynchronousQueue());
}
CachedThreadPool的corePoolSize被設(shè)置為0公般,即corePool為空;maximumPoolSize被設(shè)置為?Integer.MAX_VALUE胡桨,即maximumPool是無界的。這里把keepAliveTime設(shè)置為60L登失,意味著?CachedThreadPool中的空閑線程等待新任務(wù)的最長時間為60秒,空閑線程超過60秒后將會被終止揽浙。
FixedThreadPool和SingleThreadExecutor使用無界隊列LinkedBlockingQueue作為線程池的工作隊列状婶。CachedThreadPool使用沒有容量的SynchronousQueue作為線程池的工作隊列,但?CachedThreadPool的maximumPool是無界的膛虫。這意味著,如果主線程提交任務(wù)的速度高于?maximumPool中線程處理任務(wù)的速度時稍刀,CachedThreadPool會不斷創(chuàng)建新線程撩独。極端情況下账月,?CachedThreadPool會因為創(chuàng)建過多線程而耗盡CPU和內(nèi)存資源综膀。
CachedThreadPool的execute()方法的執(zhí)行示意圖如圖所示局齿。
對上圖的說明如下剧劝。
????1)首先執(zhí)行SynchronousQueue.offer(Runnable?task)抓歼。如果當(dāng)前maximumPool中有空閑線程正在執(zhí)行? ?????SynchronousQueue.poll(keepAliveTime讥此,TimeUnit.NANOSECONDS)谣妻,那么主線程執(zhí)行offer操作與空閑線? ?????程執(zhí)行的poll操作配對成功萄喳,主線程把任務(wù)交給空閑線程執(zhí)行蹋半,execute()方法執(zhí)行完成他巨;否則執(zhí)行下面的步驟
????2)當(dāng)初始maximumPool為空湃窍,或者maximumPool中當(dāng)前沒有空閑線程時闻蛀,將沒有線程執(zhí)? ?????行?SynchronousQueue.poll(keepAliveTime您市,TimeUnit.NANOSECONDS)役衡。這種情況下茵休,步驟1)將失敗手蝎。? ?????此時CachedThreadPool會創(chuàng)建一個新線程執(zhí)行任務(wù)榕莺,execute()方法執(zhí)行完成棵介。
????3)在步驟2)中新創(chuàng)建的線程將任務(wù)執(zhí)行完后钉鸯,會執(zhí)行?SynchronousQueue.poll(keepAliveTime,? ?????TimeUnit.NANOSECONDS)邮辽。這個poll操作會讓空閑線程最多在SynchronousQueue中等待60秒鐘唠雕。如果60? ?????秒鐘內(nèi)主線程提交了一個新任務(wù)(主線程執(zhí)行步驟1))贸营,那么這個空閑線程將執(zhí)行主線程提交的新任務(wù);否? ?????則岩睁,這個空閑線程將終止钞脂。由于空閑60秒的空閑線程會被終止,因此長時間保持空閑的CachedThreadPool不? ? ????會使用任何資源捕儒。
前面提到過冰啃,SynchronousQueue是一個沒有容量的阻塞隊列。每個插入操作必須等待另一個線程的對應(yīng)移除操作刘莹,反之亦然阎毅。CachedThreadPool使用SynchronousQueue,把主線程提交的任務(wù)傳遞給空閑線程執(zhí)行栋猖。CachedThreadPool中任務(wù)傳遞的示意圖如圖所示净薛。