天天看點

定制并發類(六)自定義在計劃的線程池内運作的任務

自定義在計劃的線程池内運作的任務

計劃的線程池是 executor 架構的基本線程池的擴充,允許你定制一個計劃來執行一段時間後需要被執行的任務。 它通過 scheduledthreadpoolexecutor 類來實作,并允許運作以下這兩種任務:

delayed 任務:這種任務在一段時間後僅執行一次。

periodic 任務:這種任務在延遲後執行,然後通常周期性運作

delayed 任務可以執行 callable 和 runnable 對象,但是 periodic任務隻能執行 runnable 對象。全部任務通過計劃池執行的都必須實作 runnablescheduledfuture 接口。在這個指南,你将學習如何實作你自己的 runnablescheduledfuture 接口來執行延遲和周期性任務。

準備

指南中的例子是使用eclipse ide 來實作的。如果你使用eclipse 或者其他的ide,例如netbeans, 打開并建立一個新的java項目。

怎麼做呢…

按照這些步驟來實作下面的例子:

它是怎麼工作的…

在這個指南,你實作了 myscheduledtask 類實作在 scheduledthreadpoolexecutor 執行者中執行的自定義任務。這個類擴充 futuretask 類并實作了 runnablescheduledfuture 接口。它實作 runnablescheduledfuture 接口, 因為在計劃的執行者中執行的全部任務都一定要實作 這個接口,并擴充了 futuretask 類,因為這個類提供了能有效的實作在 runnablescheduledfuture 接口聲明的方法。 之前提到的全部接口和類都被參數化成任務要傳回的資料類型。

為了在計劃的執行者中使用 myscheduledtask 任務,要重寫在 myscheduledthreadpoolexecutor 類的 decoratetask() 方法。這個類擴充 scheduledthreadpoolexecutor 執行者和它的方法提供一個把 scheduledthreadpoolexecutor 執行者預設的計劃任務轉換成 myscheduledtask 任務來實作的機制。是以,當你實作你的版本的計劃任務時,你必須實作你的版本的計劃的執行者。

decoratetask() 方法隻是簡單的建立了新的帶有參數的 myscheduledtask 對象:将要在任務中執行的 runnable 對象; 将被任務傳回結果對象,在這個例子,任務将不會傳回結果,是以你要使用null值;原來執行 runnable 對象的任務,新的對象将在池中代替這個任務;和

将執行任務的執行者,在這個例子,你使用 this 關鍵詞指向建立這個任務的執行者。

the myscheduledtask 類可以執行延遲和周期性任務。你已經實作了有全部必須的算法可以執行這2種任務的方法。他們是 getdelay() 和 run() 方法。

the getdelay() 方法被計劃的執行者調用來确認它是否需要運作任務。此方法對延遲任務和周期任務的響應是不同的。在之前提到的, myscheduledclass 類的構造函數接收 原先的将要執行 runnable 對象的 scheduledrunnablefuture 對象, 并儲存它作為類的屬性來擷取它的方法和它的資料。當我們要運作延遲任務時,getdelay() 方法傳回原先任務的延遲,但是在周期任務的例子中,getdelay() 方法傳回 startdate 屬性值與目前時間的相內插補點。

run() 方法是用來執行任務的。周期性任務的一個特别之處是你必須把下一次任務的執行作為一個新的任務放入到執行者的queue中,如果你要再次運作任務的話。是以,如果你執行周期性任務,你确定 startdate 屬性值通過把目前時間和任務的執行周期相加,然後把任務儲存在執行者的queue中。startdate 屬性儲存下一次任務将開始運作的時間。然後,使用 futuretask 類提供的 runandreset() 方法來運作任務。 在這個例子的延遲任務由于他們僅僅執行一次,就不用把他們放入執行者的queue中了。

你必須要注意如果執行者已經關閉。在這個例子,你不不需要再次把周期性任務儲存進執行者的queue。

最後,你重寫了在 myscheduledthreadpoolexecutor 類的 scheduleatfixedrate() 方法。我們之前提到的,對于周期任務,你要使用任務的周期來确定 startdate 屬性值,但是你還沒有初始這個周期呢。你必須重寫此方法接收周期作為參數,然後傳遞給 myscheduledtask 類這樣它才能使用。

有了 task 類例子總是完成了,它實作 runnable 接口,也是在計劃的執行者中運作的任務。這個例子的主類建立了 myscheduledthreadpoolexecutor 執行者,然後給他們發送了以下2個任務:

一個延遲任務,在目前時間過一秒後運作

一個周期任務,在目前時間過一秒後運作,接着每隔3秒運作

以下裁圖展示了這個例子的運作的一部分。你可以檢查2種任務運作正常:

定制并發類(六)自定義在計劃的線程池内運作的任務

更多…

scheduledthreadpoolexecutor 類提供了另一個版本的 decoratetask() 方法,它接收 callable 對象作為參數來代替 runnable 對象。

參見

<a href="http://ifeve.com/thread-executors-7/">第四章,線程執行者:執行者在延遲後運作任務</a>

<a href="http://ifeve.com/thread-executors-8/" target="_blank">第四章,線程執行者:執行者周期性運作任務</a>