天天看點

線程執行者(十)執行者控制一個任務完成

執行者控制一個任務完成

FutureTask類提供一個done()方法,允許你在執行者執行任務完成後執行一些代碼。你可以用來做一些後處理操作,生成一個報告,通過e-mail發送結果,或釋放一些資源。當執行的任務由FutureTask來控制完成,FutureTask會内部調用這個方法。這個方法在任務的結果設定和它的狀态變成isDone狀态之後被調用,不管任務是否已經被取消或正常完成。

預設情況下,這個方法是空的。你可以重寫FutureTask類實作這個方法來改變這種行為。在這個指南中,你将學習如何重寫這個方法,在任務完成之後執行代碼。

準備工作…

這個指南的例子使用Eclipse IDE實作。如果你使用Eclipse或其他IDE,如NetBeans,打開它并建立一個新的Java項目。

如何做…

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

1.建立ExecutableTask類,并指定其實作Callable接口,參數化為String類型。

<code>1</code>

<code>public</code> <code>class</code> <code>ExecutableTask</code><code>implements</code> <code>Callable&lt;String&gt; {</code>

2.聲明一個私有的、類型為String、名為name的屬性,用來存儲任務的名稱。實作getName()方法,傳回這個屬性值。

<code>private</code> <code>String name;</code>

<code>2</code>

<code>public</code> <code>String getName(){</code>

<code>3</code>

<code>return</code> <code>name;</code>

<code>4</code>

<code>}</code>

3.實作這個類的構造器,初始化任務的名稱。

<code>public</code> <code>ExecutableTask(String name){</code>

<code>this</code><code>.name=name;</code>

4.實作call()方法。使這個任務睡眠一個随機時間,傳回任務名稱的資訊。

<code>01</code>

<code>@Override</code>

<code>02</code>

<code>public</code> <code>String call()</code><code>throws</code> <code>Exception {</code>

<code>03</code>

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

<code>04</code>

<code>long</code> <code>duration=(</code><code>long</code><code>)(Math.random()*</code><code>10</code><code>);</code>

<code>05</code>

<code>System.out.printf("%s: Waiting %d seconds</code><code>for</code> <code>results.\</code>

<code>06</code>

<code>n",</code><code>this</code><code>.name,duration);</code>

<code>07</code>

<code>TimeUnit.SECONDS.sleep(duration);</code>

<code>08</code>

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

<code>09</code>

<code>10</code>

<code>return</code> <code>"Hello, world. I'm "</code><code>+name;</code>

<code>11</code>

5.實作ResultTask類,繼承FutureTask類,參數化為String類型。

<code>public</code> <code>class</code> <code>ResultTask</code><code>extends</code> <code>FutureTask&lt;String&gt; {</code>

6.聲明一個私有的、類型為String、名為name的屬性,用來存儲任務的名稱。

7.實作這個類的構造器。它接收一個Callable對象參數。調用父類構造器,使用接收到的任務的屬性初始化name屬性。

<code>public</code> <code>ResultTask(Callable&lt;String&gt; callable) {</code>

<code>super</code><code>(callable);</code>

<code>this</code><code>.name=((ExecutableTask)callable).getName();</code>

8.重寫done()方法。檢查isCancelled()方法傳回值,并根據這個傳回值的不同,寫入不同的資訊到控制台。

<code>protected</code> <code>void</code> <code>done() {</code>

<code>if</code> <code>(isCancelled()) {</code>

<code>System.out.printf(</code><code>"%s: Has been canceled\n"</code><code>,name);</code>

<code>5</code>

<code>}</code><code>else</code> <code>{</code>

<code>6</code>

<code>System.out.printf(</code><code>"%s: Has finished\n"</code><code>,name);</code>

<code>7</code>

<code>8</code>

9.實作示例的主類,建立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>

10.使用Executors類的newCachedThreadPool()方法建立ExecutorService。

<code>ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();</code>

11.建立存儲5個ResultTask對象的一個數組。

<code>ResultTask resultTasks[]=</code><code>new</code> <code>ResultTask[</code><code>5</code><code>];</code>

12.初始化ResultTask對象。對于資料的每個位置,首先,你必須建立ExecutorTask,然後,ResultTask使用這個對象,然後,然後submit()方法送出ResultTask給執行者。

<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>ExecutableTask executableTask=</code><code>new</code> <code>ExecutableTask(</code><code>"Task "</code><code>+i);</code>

<code>resultTasks[i]=</code><code>new</code> <code>ResultTask(executableTask);</code>

<code>executor.submit(resultTasks[i]);</code>

13.令主線程睡眠5秒。

<code>TimeUnit.SECONDS.sleep(</code><code>5</code><code>);</code>

<code>}</code><code>catch</code> <code>(InterruptedException e1) {</code>

<code>e1.printStackTrace();</code>

14.取消你送出給執行者的所有任務。

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

<code>resultTasks[i].cancel(</code><code>true</code><code>);</code>

15.将沒有被使用ResultTask對象的get()方法取消的任務的結果寫入到控制台。

<code>if</code> <code>(!resultTasks[i].isCanceled()){</code>

<code>System.out.printf(</code><code>"%s\n"</code><code>,resultTasks[i].get());</code>

<code>}</code><code>catch</code> <code>(InterruptedException | ExecutionException e) {</code>

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

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

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

它是如何工作的…

當控制任務執行完成後,FutureTask類調用done()方法。在這個示例中,你已經實作一個Callable對象,ExecutableTask類,然後一個FutureTask類的子類用來控制ExecutableTask對象的執行。

在建立傳回值和改變任務的狀态為isDone狀态後,done()方法被FutureTask類内部調用。你不能改變任務的結果值和它的狀态,但你可以關閉任務使用的資源,寫日志消息,或發送通知。

參見

在第4章,線程執行者中的執行者執行傳回結果的任務指南

繼續閱讀