天天看點

線程執行者(七)執行者延遲運作一個任務

執行者延遲運作一個任務

執行者架構提供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&lt;String&gt; {</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&lt;</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章,線程執行者中的執行者執行傳回結果的任務指南

繼續閱讀