
一 用線程池好處
限制和管理資源(執(zhí)行任務(wù))。 維護(hù)統(tǒng)計(jì)信息,如已完成任務(wù)數(shù)。?
1)重復(fù)利用已創(chuàng)建線程降低線程創(chuàng)建和銷毀消耗。
2)提高響應(yīng)速度。任務(wù)到達(dá)立即執(zhí)行(不需等線程創(chuàng)建)。
3)統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控
二 Executor 框架?
2.1 簡介
Java 5之后, Executor啟動(dòng)線程比Thread 的 start 好,除了更易管理、節(jié)約開銷,避免 this 逃逸(構(gòu)造函數(shù)返回之前,其他線程就持有該對(duì)象引用. 調(diào)用未構(gòu)造完全的對(duì)象方法引發(fā)錯(cuò)誤)。
2.2 Executor 框架結(jié)構(gòu)(主要由三大部分組成)
1 任務(wù)。
Runnable接口(不返回結(jié)果)或Callable接口(返回)實(shí)現(xiàn)類都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執(zhí)行。
2 任務(wù)的執(zhí)行
核心接口Executor?,ScheduledThreadPoolExecutor和ThreadPoolExecutor兩個(gè)關(guān)鍵類實(shí)現(xiàn)了ExecutorService接口(繼承Executor)。
ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor并實(shí)現(xiàn)ScheduledExecutorService ,而ScheduledExecutorService又實(shí)現(xiàn)了ExecutorService
ThreadPoolExecutor類描述:

ScheduledThreadPoolExecutor類描述:


3 異步計(jì)算的結(jié)果
Future接口及實(shí)現(xiàn)類FutureTask類。?
把Runnable接口或Callable接口的實(shí)現(xiàn)類提交(調(diào)用submit方法)給ThreadPoolExecutor或ScheduledThreadPoolExecutor時(shí),會(huì)返回一個(gè)FutureTask對(duì)象。


2.3 Executor 框架的使用示意圖

1.主線程首先要?jiǎng)?chuàng)建實(shí)現(xiàn)Runnable或者Callable接口的任務(wù)對(duì)象。?
備注:?工具類Executors可以實(shí)現(xiàn)Runnable對(duì)象和Callable對(duì)象之間的相互轉(zhuǎn)換。
2.創(chuàng)建完成Runnable對(duì)象直接交給ExecutorService執(zhí)行(ExecutorService.execute(Runnable command));或者也可以把Runnable對(duì)象或Callable對(duì)象提交給ExecutorService執(zhí)行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable task))。
執(zhí)行execute()方法和submit()方法的區(qū)別是什么呢??
1)execute()方法提交不需要返回值任務(wù),無法判斷任務(wù)是否被線程池執(zhí)行成功與否;?
2)submit()方法用于提交需要返回值的任務(wù)。線程池會(huì)返回一個(gè)future類型的對(duì)象,判斷任務(wù)執(zhí)行成功,future的get()獲取返回值,get()會(huì)阻塞當(dāng)前線程直到任務(wù)完成,get(long timeout,TimeUnit unit)阻塞一段時(shí)間后返回,有可能沒執(zhí)行完。
3.如果執(zhí)行ExecutorService.submit(…),ExecutorService將返回一個(gè)實(shí)現(xiàn)Future接口的對(duì)象(我們剛剛也提到過了執(zhí)行execute()方法和submit()方法的區(qū)別,到目前為止的JDK中,返回的是FutureTask對(duì)象)。由于FutureTask實(shí)現(xiàn)了Runnable,程序員也可以創(chuàng)建FutureTask,然后直接交給ExecutorService執(zhí)行。
主線程FutureTask.get()等待任務(wù)執(zhí)行完成。FutureTask.cancel(boolean mayInterruptIfRunning)取消此任務(wù)的執(zhí)行。
三 ThreadPoolExecutor詳解?
Executor 最核心的類
3.1 ThreadPoolExecutor類的四個(gè)比較重要的屬性?

3.2 ThreadPoolExecutor類中提供的四個(gè)構(gòu)造方法
最長的,其余三個(gè)都是在這個(gè)構(gòu)造方法的基礎(chǔ)上產(chǎn)生(給定某些默認(rèn)參數(shù)的構(gòu)造方法)線程池飽和策略


3.3 如何創(chuàng)建ThreadPoolExecutor
方式一:通過構(gòu)造方法實(shí)現(xiàn)(建議第二種)?

方式二:通過Executor框架的工具類Executors來實(shí)現(xiàn),三種類型:
FixedThreadPool
SingleThreadExecutor
CachedThreadPool

3.4 FixedThreadPool詳解
重用固定線程數(shù)線程池。

另外FixedThreadPool實(shí)現(xiàn)方法,和上面類似

FixedThreadPool的corePoolSize和maximumPoolSize都被設(shè)置為nThreads。?

上圖說明:
當(dāng)前運(yùn)行的線程數(shù)小于corePoolSize,創(chuàng)建新線程執(zhí)行任務(wù);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?等于corePoolSize,將任務(wù)加入LinkedBlockingQueue;
執(zhí)行完1中任務(wù),循環(huán)從LinkedBlockingQueue獲取執(zhí)行;
無界隊(duì)列 LinkedBlockingQueue(容量為Intger.MAX_VALUE)影響:?
1. 達(dá)到corePoolSize后,新任務(wù)在無界隊(duì)列中等待
2. maximumPoolSize、keepAliveTime無效參數(shù);?
3. 運(yùn)行中FixedThreadPool(未執(zhí)行shutdown()或shutdownNow()方法)不拒絕任務(wù)
3.5 SingleThreadExecutor詳解
單個(gè)worker線程Executor

corePoolSize和maximumPoolSize都為1.其他參數(shù)、LinkedBlockingQueue、執(zhí)行圖(流程)和FixedThreadPool相同。

3.6 CachedThreadPool詳解
根據(jù)需要創(chuàng)建新線程的線程池

corePoolSize設(shè)置空(0),maximumPoolSize被設(shè)置為Integer.MAX.VALUE,是無界,主線程提交任務(wù)速度高于maximumPool處理速度時(shí),CachedThreadPool不斷創(chuàng)建新線程。極端會(huì)耗盡cpu和內(nèi)存資源。

上圖說明:?
1. 先執(zhí)行SynchronousQueue.offer(Runnable task)。如果當(dāng)前maximumPool中有閑線程正在執(zhí)行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那么主線程執(zhí)行offer操作與空閑線程執(zhí)行的poll操作配對(duì)成功,主線程把任務(wù)交給空閑線程執(zhí)行,execute()完成,否則執(zhí)行步驟2;?
2. 初始maximumPool為空,或maximumPool沒有空閑線程時(shí),將沒線程執(zhí)行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。步驟1將失敗,CachedThreadPool創(chuàng)建新線程execute完成;
3.7 ThreadPoolExecutor使用示例
3.7.1 示例代碼
創(chuàng)建Runnable接口實(shí)現(xiàn)類(也可Callable接口)

編寫測試程序,F(xiàn)ixedThreadPool為例


3.7.2 shutdown()VS shutdownNow()
shutdown():關(guān)閉在Executor上調(diào)用,不再向DelayedPool添加任何其他任務(wù)(由ScheduledThreadPoolExecutor類在內(nèi)部使用)。隊(duì)列中提交任務(wù)允許完成。?
shutdownNow():終止當(dāng)前正在運(yùn)行的任務(wù),并停止處理排隊(duì)任務(wù)并返回正在等待執(zhí)行的List。
3.7.3 isTerminated() Vs isShutdown()
isShutDown:shutdown()或shutdownNow()返回為true
isTerminated:?關(guān)閉后所有任務(wù)都已完成,返回true。除非首先調(diào)用shutdown或shutdownNow,否則isTerminated永不為true。
四 ScheduledThreadPoolExecutor詳解?
4.1 簡介
定期執(zhí)行任務(wù)。任務(wù)隊(duì)列DelayQueue封裝了一個(gè)PriorityQueue排序隊(duì)列任務(wù),時(shí)間短先執(zhí)行(ScheduledFutureTask的time變量小),時(shí)間相同則先提交先執(zhí)行(ScheduledFutureTask的squenceNumber變量小)。
ScheduledThreadPoolExecutor和Timer的比較:
ScheduledThreadPoolExecutor:不敏感;任意數(shù)量線程(控制創(chuàng)建);捕獲運(yùn)行異常,需要時(shí)處理(重寫afterExecute方法 ThreadPoolExecutor)。拋出異常任務(wù)取消,其他繼續(xù)運(yùn)行。
Timer:時(shí)鐘變化敏感;一個(gè)線程;運(yùn)行異常會(huì)殺死線程,死機(jī);JDK1.5之后,不用Timer
4.2 ScheduledThreadPoolExecutor運(yùn)行機(jī)制

ScheduledThreadPoolExecutor的執(zhí)行主要分為兩大部分:
1.當(dāng)調(diào)用ScheduledThreadPoolExecutor的?scheduleAtFixedRate()?方法或者scheduleWirhFixedDelay()?方法時(shí),會(huì)向ScheduledThreadPoolExecutor的?DelayQueue?添加一個(gè)實(shí)現(xiàn)了?RunnableScheduledFutur?接口的?ScheduledFutureTask?。
2.線程池中的線程從DelayQueue中獲取ScheduledFutureTask,然后執(zhí)行任務(wù)。
ScheduledThreadPoolExecutor為了實(shí)現(xiàn)周期性的執(zhí)行任務(wù),對(duì)ThreadPoolExecutor做了如下修改:
1使用?DelayQueue?作為任務(wù)隊(duì)列;
2獲取任務(wù)的方不同
3執(zhí)行周期任務(wù)后,增加了額外的處理

1.線程1從DelayQueue中獲取已到期的ScheduledFutureTask(DelayQueue.take())。到期任務(wù)是指ScheduledFutureTask的time大于等于當(dāng)前系統(tǒng)的時(shí)間;
2.線程1執(zhí)行這個(gè)ScheduledFutureTask;
3.線程1修改ScheduledFutureTask的time變量為下次將要被執(zhí)行的時(shí)間;
4.線程1把這個(gè)修改time之后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())。
4.4 ScheduledThreadPoolExecutor使用示例
Runnable接口的類(我們上面的例子已經(jīng)實(shí)現(xiàn)過)
ScheduledExecutorService和ScheduledThreadPoolExecutor實(shí)現(xiàn)java調(diào)度。


4.4.1 ScheduledExecutorService scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法
我們可以使用ScheduledExecutorService scheduleAtFixedRate方法來安排任務(wù)在初始延遲后運(yùn)行,然后在給定的時(shí)間段內(nèi)運(yùn)行。
時(shí)間段是從池中第一個(gè)線程的開始,因此如果您將period指定為1秒并且線程運(yùn)行5秒,那么只要第一個(gè)工作線程完成執(zhí)行,下一個(gè)線程就會(huì)開始執(zhí)行。


輸出示例:

4.4.2 ScheduledExecutorService scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法
ScheduledExecutorService scheduleWithFixedDelay方法可用于以初始延遲啟動(dòng)周期性執(zhí)行,然后以給定延遲執(zhí)行。 延遲時(shí)間是線程完成執(zhí)行的時(shí)間。



4.4.3 scheduleWithFixedDelay() vs scheduleAtFixedRate()
scheduleAtFixedRate(…)將延遲視為兩個(gè)任務(wù)開始之間的差異(即定期調(diào)用)?
scheduleWithFixedDelay(…)將延遲視為一個(gè)任務(wù)結(jié)束與下一個(gè)任務(wù)開始之間的差異
scheduleAtFixedRate():?創(chuàng)建并執(zhí)行在給定的初始延遲之后,隨后以給定的時(shí)間段首先啟用的周期性動(dòng)作; 那就是執(zhí)行將在initialDelay之后開始,然后initialDelay+period ,然后是initialDelay + 2 * period ,等等。 如果任務(wù)的執(zhí)行遇到異常,則后續(xù)的執(zhí)行被抑制。 否則,任務(wù)將僅通過取消或終止執(zhí)行人終止。 如果任務(wù)執(zhí)行時(shí)間比其周期長,則后續(xù)執(zhí)行可能會(huì)遲到,但不會(huì)同時(shí)執(zhí)行。?
scheduleWithFixedDelay() :?創(chuàng)建并執(zhí)行在給定的初始延遲之后首先啟用的定期動(dòng)作,隨后在一個(gè)執(zhí)行的終止和下一個(gè)執(zhí)行的開始之間給定的延遲。 如果任務(wù)的執(zhí)行遇到異常,則后續(xù)的執(zhí)行被抑制。 否則,任務(wù)將僅通過取消或終止執(zhí)行終止。
五 各種線程池的適用場景介紹
FixedThreadPool:限制當(dāng)前線程數(shù)。適用負(fù)載比較重服務(wù)器;
SingleThreadExecutor:順序執(zhí)行單線程
CachedThreadPool:短期異步小程序,負(fù)載輕服務(wù)器;
ScheduledThreadPoolExecutor:后臺(tái)周期任務(wù),限制線程數(shù)
SingleScheduledThreadExecutor:單個(gè)后臺(tái)周期任務(wù),順序執(zhí)行