(八)線程池與Executor 框架(太老半廢棄掉)

一 用線程池好處

限制管理資源(執(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)類都可以被ThreadPoolExecutorScheduledThreadPoolExecutor執(zhí)行。

2 任務(wù)的執(zhí)行

核心接口Executor?,ScheduledThreadPoolExecutorThreadPoolExecutor兩個(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方法)給ThreadPoolExecutorScheduledThreadPoolExecutor時(shí),會(huì)返回一個(gè)FutureTask對(duì)象。

newTaskFor方法返回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

對(duì)應(yīng)Executors工具類中方法? ?

3.4 FixedThreadPool詳解

重用固定線程數(shù)線程池。

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

FixedThreadPool的corePoolSizemaximumPoolSize都被設(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í)行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容