天天看點

線程執行者(八)執行者周期性地運作一個任務

執行者周期性地運作一個任務

執行者架構提供threadpoolexecutor類,使用池中的線程執行并發任務,進而避免所有線程的建立操作。當你送出任務給執行者,根據它的配置,它盡快地執行任務。當它結束,任務将被執行者删除,如果你想再次運作任務,你必須再次送出任務給執行者。

但是執行者架構通過scheduledthreadpoolexecutor類可以執行周期性任務。在這個指南中,你将學習如何通過使用這個類的功能來安排一個周期性任務。

準備工作…

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

如何做…

按以下步驟來實作的這個例子:

1.建立task類,并指定它實作runnable接口。

<code>1</code>

<code>public</code> <code>class</code> <code>task </code><code>implements</code> <code>runnable {</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.實作run()方法,寫入實際日期到控制台,檢查任務在指定的時間内執行。

<code>@override</code>

<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>4</code>

<code>return</code> <code>"hello, world"</code><code>;</code>

<code>5</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>scheduledexecutorservice executor=executors.newscheduledthreadpool(</code><code>1</code><code>);</code>

7.寫入實際日期到控制台。

<code>system.out.printf(</code><code>"main: starting at: %s\n"</code><code>,</code><code>new</code> <code>date());</code>

8.建立一個新的task對象。

<code>task task=</code><code>new</code> <code>task(</code><code>"task"</code><code>);</code>

9.使用scheduledatfixrate()方法把它送出給執行者。使用前面建立的任務,數字1,數字2和常量timeunit.seconds作為參數。這個方法傳回scheduledfuture對象,它可以用來控制任務的狀态。

<code>scheduledfuture&lt;?&gt; result=executor.scheduleatfixedrate(task,</code><code>1</code><code>, </code><code>2</code><code>, timeunit.seconds);</code>

10.建立10個循環步驟,寫入任務下次執行的剩餘時間。在循環中,使用scheduledfuture對象的getdelay()方法,擷取任務下次執行的毫秒數。

<code>01</code>

<code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i&lt;</code><code>10</code><code>; i++){</code>

<code>02</code>

<code>system.out.printf(</code><code>"main: delay: %d\n"</code><code>,result.</code>

<code>03</code>

<code>getdelay(timeunit.milliseconds));</code>

<code>04</code>

<code>//線程睡眠500毫秒</code>

<code>05</code>

<code>try</code> <code>{</code>

<code>06</code>

<code>timeunit.milliseconds.sleep(</code><code>500</code><code>);</code>

<code>07</code>

<code>} </code><code>catch</code> <code>(interruptedexception e) {</code>

<code>08</code>

<code>e.printstacktrace();</code>

<code>09</code>

<code>10</code>

11.使用shutdown()方法關閉執行者。

<code>executor.shutdown();</code>

12.使線程睡眠5秒,檢查周期性任務是否完成。

<code>timeunit.seconds.sleep(</code><code>5</code><code>);</code>

13.寫入一條資訊到控制台,表明程式結束。

<code>system.out.printf(</code><code>"main: finished at: %s\n"</code><code>,</code><code>new</code> <code>date());</code>

它是如何工作的…

當你想要使用執行者架構執行一個周期性任務,你需要scheduledexecutorservice對象。java建議使用 executors類建立執行者,executors類是一個執行者對象工廠。在本例中,你應該使用newscheduledthreadpool()方法,建立一個 scheduledexecutorservice對象。這個方法接收池的線程數作為參數。正如在本例中你隻有一個任務,你傳入了值1作為參數。

一旦你有執行者需要執行一個周期性任務,你送出任務給該執行者。你已經使用了scheduledatfixedrate()方法。此方法接收4個參數:你想要周期性執行的任務、第一次執行任務的延遲時間、兩次執行之間的間隔期間、第2、3個參數的時間機關。它是timeunit類的常 量,timeunit類是個枚舉類,有如下常量:days,hours,microseconds, milliseconds, minutes,,nanoseconds 和seconds。

很重要的一點需要考慮的是兩次執行之間的(間隔)期間,是這兩個執行開始之間的一段時間。如果你有一個花5秒執行的周期性任務,而你給一段3秒時間,同一時刻,你将會有兩個任務在執行。

scheduleatfixedrate() 方法傳回scheduledfuture對象,它繼承future接口,這個方法和排程任務一起協同工作。scheduledfuture是一個參數化接口(校對注:scheduledfuture&lt;v&gt;)。在這個示例中,由于你的任務是非參數化的runnable對象,你必須使用 問号作為參數。

你已經使用scheduledfuture接口的一個方法。getdelay()方法傳回直到任務的下次執行時間。這個方法接收一個timeunit常量,這是你想要接收結果的時間機關。

以下截圖顯示這個示例執行的輸出:

線程執行者(八)執行者周期性地運作一個任務

你可以看出用task:作為字首的任務每2秒執行一次,并且每示範500毫秒向控制台寫入一次。這就是main線程睡眠的時間。當你關閉執行者,這個計劃任務結束它的執行,你将不會在控制台看到更多的資訊。

不止這些…

scheduledthreadpoolexecutor 提供其他方法來排程周期性任務。這就是schedulewithfixedrate()方法。它與scheduledatfixedrate()方法有一 樣的參數,但它們之間的差異值得注意。在scheduledatfixedrate()方法中,第3個參數決定兩個執行開始的一段時間。在 scheduledwithfixedrate()方法中,參數決定任務執行結束與下次執行開始之間的一段時間。

當你使用 shutdown()方法時,你也可以通過參數配置一個seduledthreadpoolexecutor的行為。shutdown()方法預設的行為是,當你調用這個方法時,計劃任務就結束。 你可以使用scheduledthreadpoolexecutor類的 setcontinueexistingperiodictasksaftershutdownpolicy()方法設定true值改變這個行為。在調用 shutdown()方法時,周期性任務将不會結束。

參見

在第4章,線程執行者中的建立一個線程執行者食譜

在第4章,線程執行者中的執行者延遲運作一個任務食譜

繼續閱讀