執行緒執行者(十)執行者控制一個任務完成
宣告:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González 譯者:許巧輝 校對:方騰飛,葉磊
執行者控制一個任務完成
FutureTask類提供一個done()方法,允許你在執行者執行任務完成後執行一些程式碼。你可以用來做一些後處理操作,生成一個報告,通過e-mail傳送結果,或釋放一些資源。當執行的任務由FutureTask來控制完成,FutureTask會內部呼叫這個方法。這個方法在任務的結果設定和它的狀態變成isDone狀態之後被呼叫,不管任務是否已經被取消或正常完成。
預設情況下,這個方法是空的。你可以重寫FutureTask類實現這個方法來改變這種行為。在這個指南中,你將學習如何重寫這個方法,在任務完成之後執行程式碼。
準備工作…
這個指南的例子使用Eclipse IDE實現。如果你使用Eclipse或其他IDE,如NetBeans,開啟它並建立一個新的Java專案。
如何做…
按以下步驟來實現的這個例子:
1.建立ExecutableTask類,並指定其實現Callable介面,引數化為String型別。
public class ExecutableTask implements Callable<String> {
2.宣告一個私有的、型別為String、名為name的屬性,用來儲存任務的名稱。實現getName()方法,返回這個屬性值。
private String name; public String getName(){ return name; }
3.實現這個類的構造器,初始化任務的名稱。
public ExecutableTask(String name){ this.name=name; }
4.實現call()方法。使這個任務睡眠一個隨機時間,返回任務名稱的資訊。
@Override public String call() throws Exception { try { long duration=(long)(Math.random()*10); System.out.printf("%s: Waiting %d seconds for results.\ n",this.name,duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { } return "Hello, world. I'm "+name; }
5.實現ResultTask類,繼承FutureTask類,引數化為String型別。
public class ResultTask extends FutureTask<String> {
6.宣告一個私有的、型別為String、名為name的屬性,用來儲存任務的名稱。
private String name;
7.實現這個類的構造器。它接收一個Callable物件引數。呼叫父類構造器,使用接收到的任務的屬性初始化name屬性。
public ResultTask(Callable<String> callable) { super(callable); this.name=((ExecutableTask)callable).getName(); }
8.重寫done()方法。檢查isCancelled()方法返回值,並根據這個返回值的不同,寫入不同的資訊到控制檯。
@Override protected void done() { if (isCancelled()) { System.out.printf("%s: Has been canceled\n",name); } else { System.out.printf("%s: Has finished\n",name); } }
9.實現示例的主類,建立Main類,實現main()方法。
public class Main { public static void main(String[] args) {
10.使用Executors類的newCachedThreadPool()方法建立ExecutorService。
ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();
11.建立儲存5個ResultTask物件的一個數組。
ResultTask resultTasks[]=new ResultTask[5];
12.初始化ResultTask物件。對於資料的每個位置,首先,你必須建立ExecutorTask,然後,ResultTask使用這個物件,然後,然後submit()方法提交ResultTask給執行者。
for (int i=0; i<5; i++) { ExecutableTask executableTask=new ExecutableTask("Task "+i); resultTasks[i]=new ResultTask(executableTask); executor.submit(resultTasks[i]); }
13.令主執行緒睡眠5秒。
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e1) { e1.printStackTrace(); }
14.取消你提交給執行者的所有任務。
for (int i=0; i<resultTasks.length; i++) { resultTasks[i].cancel(true); }
15.將沒有被使用ResultTask物件的get()方法取消的任務的結果寫入到控制檯。
for (int i=0; i<resultTasks.length; i++) { try { if (!resultTasks[i].isCanceled()){ System.out.printf("%s\n",resultTasks[i].get()); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }
16.使用shutdown()方法關閉執行者。
executor.shutdown(); } }
它是如何工作的…
當控制任務執行完成後,FutureTask類呼叫done()方法。在這個示例中,你已經實現一個Callable物件,ExecutableTask類,然後一個FutureTask類的子類用來控制ExecutableTask物件的執行。
在建立返回值和改變任務的狀態為isDone狀態後,done()方法被FutureTask類內部呼叫。你不能改變任務的結果值和它的狀態,但你可以關閉任務使用的資源,寫日誌訊息,或傳送通知。
參見
- 在第4章,執行緒執行者中的執行者執行返回結果的任務指南