執行者延遲運作一個任務
執行者架構提供threadpoolexecutor類,使用池中的線程來執行callable和runnable任務,這樣可以避免所有線程的建立操作。當你送出一個任務給執行者,會根據執行者的配置盡快執行它。在有些使用情況下,當你對盡快執行任務不感覺興趣。你可能想要在一段時間之後執行任務或周期性地執行任務。基于這些目的,執行者架構提供 scheduledthreadpoolexecutor類。
在這個指南中,你将學習如何建立scheduledthreadpoolexecutor和如何使用它安排任務在指定的時間後執行。
準備工作…
這個指南的例子使用eclipse ide實作。如果你使用eclipse或其他ide,如netbeans,打開它并建立一個新的java項目。
如何做…
按以下步驟來實作的這個例子:
1.建立task類,實作callable接口,參數化為string類型。
<code>1</code>
<code>public</code> <code>class</code> <code>task</code><code>implements</code> <code>callable<string> {</code>
2.聲明一個私有的、類型為string、名為name的屬性,用來存儲任務的名稱。
<code>private</code> <code>string name;</code>
3.實作task類的構造器,初始化name屬性。
<code>public</code> <code>task(string name) {</code>
<code>2</code>
<code>this</code><code>.name=name;</code>
<code>3</code>
<code>}</code>
4.實作call()方法,寫入實際日期到控制台,傳回一個文本,如:hello, world。
<code>public</code> <code>string call()</code><code>throws</code> <code>exception {</code>
<code>system.out.printf(</code><code>"%s: starting at : %s\n"</code><code>,name,</code><code>new</code> <code>date());</code>
<code>return</code> <code>"hello, world"</code><code>;</code>
<code>4</code>
5.實作示例的主類,建立main類,實作main()方法。
<code>public</code> <code>class</code> <code>main {</code>
<code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>
6.使用executors類的newscheduledthreadpool()方法,建立scheduledthreadpoolexecutor類的一個執行者。傳入參數1。
<code>scheduledthreadpoolexecutor executor=(scheduledthreadpoolexecutor)executors.newscheduledthreadpool(</code><code>1</code><code>);</code>
7.使用scheduledthreadpoolexecutor執行個體的schedule()方法,初始化和開始一些任務(本例中5個任務)。
<code>system.out.printf(</code><code>"main: starting at: %s\n"</code><code>,</code><code>new</code> <code>date());</code>
<code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i<</code><code>5</code><code>; i++) {</code>
<code>task task=</code><code>new</code> <code>task(</code><code>"task "</code><code>+i);</code>
<code>executor.schedule(task,i+</code><code>1</code> <code>, timeunit.seconds);</code>
<code>5</code>
8.使用shutdown()方法關閉執行者。
<code>executor.shutdown();</code>
9.使用執行者的awaittermination()方法,等待所有任務完成。
<code>try</code> <code>{</code>
<code>executor.awaittermination(</code><code>1</code><code>, timeunit.days);</code>
<code>}</code><code>catch</code> <code>(interruptedexception e) {</code>
<code>e.printstacktrace();</code>
10.寫入一條資訊表明程式結束時間。
<code>system.out.printf(</code><code>"main: ends at: %s\n"</code><code>,</code><code>new</code> <code>date());</code>
它是如何工作的…
在這個示例中,關鍵的一點是main類和scheduledthreadpoolexecutor的管理。正如使用threadpoolexecutor類建立預定的執行者,java建議利用executors類。在本例中,你使用newscheduledthreadpool()方法。你用1作為參數傳給這個方法。這個參數是你想要讓線程池建立的線程數。
你必須使用schedule()方法,讓執行者在一段時間後執行任務。這個方法接收3個參數,如下:
你想要執行的任務
你想要讓任務在執行前等待多長時間
時間機關,指定為timeunit類的常數
在本例中,每個任務等待的秒數(timeunit.seconds)等于它在任務數組中的位置再加1。
注意事項:如果你想在給定時間執行一個任務,計算這個日期與目前日期的差異,使用這個差異作為任務的延遲。
以下截圖顯示這個示例執行的輸出:

你可以看出這些任務是如何開始執行的,一秒執行一個。所有任務都是同時送出給執行者的,但每個任務比之前的任務都有1秒的延遲。
不止這些…
你也可以使用runnable接口實作任務,因為scheduledthreadpoolexecutor類的schedule()方法接收這兩種類型(runnable和callable)的任務。
盡管scheduledthreadpoolexecutor類是threadpoolexecutor類的子類,是以,它繼承 threadpoolexecutor類的所有功能,但java建議使用scheduledthreadpoolexecutor僅适用于排程任務。
最後,你可以配置scheduledthreadpoolexecutor的行為,當你調用shutdown()方法時,并且有待處理的任務正在等待它們延遲結束。預設的行為是,不管執行者是否結束這些任務都将被執行。你可以使用scheduledthreadpoolexecutor類的setexecuteexistingdelayedtasksaftershutdownpolicy()方法來改變這種行為。使用false,調用 shutdown()時,待處理的任務不會被執行。
參見
在第4章,線程執行者中的執行者執行傳回結果的任務指南