閱讀971 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

聲明:本文是《 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類型。

1 public class ExecutableTask implements Callable<String> {

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

1 private String name;
2 public String getName(){
3 return name;
4 }

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

1 public ExecutableTask(String name){
2 this.name=name;
3 }

4.實現call()方法。使這個任務睡眠一個隨機時間,返回任務名稱的信息。

01 @Override
02 public String call() throws Exception {
03 try {
04 long duration=(long)(Math.random()*10);
05 System.out.printf("%s: Waiting %d seconds for results.\
06 n",this.name,duration);
07 TimeUnit.SECONDS.sleep(duration);
08 catch (InterruptedException e) {
09 }
10 return "Hello, world. I'm "+name;
11 }

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

1 public class ResultTask extends FutureTask<String> {

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

1 private String name;

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

1 public ResultTask(Callable<String> callable) {
2 super(callable);
3 this.name=((ExecutableTask)callable).getName();
4 }

8.重寫done()方法。檢查isCancelled()方法返回值,並根據這個返回值的不同,寫入不同的信息到控製台。

1 @Override
2 protected void done() {
3 if (isCancelled()) {
4 System.out.printf("%s: Has been canceled\n",name);
5 else {
6 System.out.printf("%s: Has finished\n",name);
7 }
8 }

9.實現示例的主類,創建Main類,實現main()方法。

1 public class Main {
2 public static void main(String[] args) {

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

1 ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();

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

1 ResultTask resultTasks[]=new ResultTask[5];

12.初始化ResultTask對象。對於數據的每個位置,首先,你必須創建ExecutorTask,然後,ResultTask使用這個對象,然後,然後submit()方法提交ResultTask給執行者。

1 for (int i=0; i<5; i++) {
2 ExecutableTask executableTask=new ExecutableTask("Task "+i);
3 resultTasks[i]=new ResultTask(executableTask);
4 executor.submit(resultTasks[i]);
5 }

13.令主線程睡眠5秒。

1 try {
2 TimeUnit.SECONDS.sleep(5);
3 catch (InterruptedException e1) {
4 e1.printStackTrace();
5 }

14.取消你提交給執行者的所有任務。

1 for (int i=0; i<resultTasks.length; i++) {
2 resultTasks[i].cancel(true);
3 }

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

01 for (int i=0; i<resultTasks.length; i++) {
02 try {
03 if (!resultTasks[i].isCanceled()){
04 System.out.printf("%s\n",resultTasks[i].get());
05 }
06 catch (InterruptedException | ExecutionException e) {
07 e.printStackTrace();
08 }
09  
10 }

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

1 executor.shutdown();
2 }
3 }

它是如何工作的…

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

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

參見

最後更新:2017-05-23 19:31:53

  上一篇:go  JVM實用參數(八)GC日誌
  下一篇:go  JVM實用參數(四)內存調優