1. 程式人生 > >Executor框架(七)Future 接口、FutureTask類

Executor框架(七)Future 接口、FutureTask類

bmi true 直接 重置 真的 出現 args span 操作

Future接口介紹

??Future 表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。
??Future 一般由 ExecutorService 的submit()、invokeAll()方法返回的,用於跟蹤、獲取任務在線程池中的運行情況、等待運算結果,還可以取消任務。(還有其子接口 ScheduleFuture 則由 ScheduleExecutorService 的schedule()等方法返回);

方法描述

boolean cancel(boolean mayInterruptIfRunning):

試圖取消對此任務的執行。分成以下三種情況:

  • 如果任務尚未啟動,則此任務將永不運行。
  • 如果任務已經啟動,則 mayInterruptIfRunning 參數確定是否 中斷這個任務來嘗試停止任務。同時,任務也應該要對中斷敏感。
  • 任務已完成、或已取消,或者由於某些其他原因而無法取消,返回false。

註意: 此方法返回後,對 isDone() 的後續調用將始終返回 true。但如果此方法返回 true,則對 isCancelled() 的後續調用才將始終返回

boolean isCancelled(): 如果在任務正常完成前將其取消,則返回 true。

boolean isDone(): 如果任務已完成,則返回 true。 可能由於正常終止、異常或取消而完成,在所有這些情況中,此方法都將返回 true。

獲取計算結果
??獲取計算結果的方法,JDK提供了兩個方法:阻塞獲取 與 超時等待獲取。這兩個方法會拋出 CancellationException(任務被取消時)、InterruptedException
V get(): 等待計算完成,然後獲取其結果。
V get(long timeout,TimeUnit unit): 最多等待為使計算完成所給定的時間之後,獲取其結果(如果結果可用)。

@ Example 示例

??下面的例子,是在單線程的線程池中提交兩個任務(任務A、任務B)。

public class Test {
  public static void main(String[] args) throws
InterruptedException, ExecutionException { //單線程的線程池 ExecutorService executor = Executors.newSingleThreadExecutor(); //提交兩個任務 Future futureA = executor.submit(new MyCallable("futureA")); Future futureB = executor.submit(new MyCallable("futureB")); Thread.sleep(1000); //在運行一秒後,判斷任務A是否完成 if(futureA.isDone()){ //如果完成,則直接獲取結果 double result = (double) futureA.get(); System.out.println("運算結果是:"+result); }else{ //如果沒有完成,則取消任務A boolean b = futureA.cancel(false); System.out.println("futureA 執行了cancel方法,返回的值是:"+b); } //取消任務B futureB.cancel(false); } } class MyCallable implements Callable{ String taskName; public MyCallable(String taskName){ this.taskName = taskName; } @Override public Object call() { try { //模擬任務的執行時間為 2s for(int i=0;i<5;i++){ Thread.sleep(400); System.out.println(taskName+"任務正在運行中....."); } } catch (InterruptedException e) { e.printStackTrace(); } double d = Math.random() * 10; return d; } }

運行結果:

futureA任務正在運行中.....
futureA任務正在運行中.....
futureA 執行了cancel方法,返回的值是:true
futureA任務正在運行中.....
futureA任務正在運行中.....
futureA任務正在運行中.....

??任務A是在執行時被取消的,調用的cancel(false) 方法返回的結果為true,但是任務並沒有真的停止執行。任務B則是在還沒被執行時取消的,所以任務B在後續的時間內,沒有執行。
??可以得出結論,cancel( false)方法是取消尚未被執行的任務、周期任務,而不是停止正在執行的任務。當然,如果想要停止正在執行的任務,任務裏面必須是中斷敏感,然後 cancel(true),參數為true,即在cancel的同時,也發出中斷信號。

//簡單的中斷處理,發現中斷退出
public void run(){
    while(!Thread.interrupted()){
        //.....
    }
}


FutureTask 介紹

??FutureTask 是一個可取消的異步計算任務,是一個獨立的類,實現了 Future、Runnable接口。FutureTask 的出現是為了彌補 Thread 的不足而設計的,可以讓程序員跟蹤、獲取任務的執行情況、計算結果
??因為 FutureTask 實現了 Runnable,所以 FutureTaskk 可以作為參數來創建一個新的線程來執行,也可以提交給 Executor 執行。FutureTask 一旦計算完成,就不能再重新開始或取消計算。

構造方法

FutureTask(Callable
創建一個 FutureTask,一旦運行就執行給定的 Callable。
FutureTask(Runnable runnable, V result)
創建一個 FutureTask,一旦運行就執行給定的 Runnable,並安排成功完成時 get 返回給定的結果 。

應用場景

FutureTask 可用於異步獲取執行結果或可以取消執行任務的場景;

@ Example 簡單例子

??下面的例子中,因為計算數據的時間比較長,所以main線程就額外起一個異步線程來計算數據,從而使得計算數據的同時,main線程可以做其他工作,直到需要用到計算結果時,才去獲取計算結果。
??需要註意的是,線程 thread2 並沒有執行 FutureTask,因為 FutureTask 已經在線程 thread 中完成了。一旦 FutureTask 計算完成,就不能再重新開始或取消計算。

public class Test {
  public static void main(String[] args) throws InterruptedException, ExecutionException {
    FutureTask<Double> task = new FutureTask(new MyCallable());
    //創建一個線程,異步計算結果
    Thread thread = new Thread(task);
    thread.start();
    //主線程繼續工作
    Thread.sleep(1000);
    System.out.println("主線程等待計算結果...");
    //當需要用到異步計算的結果時,阻塞獲取這個結果
    Double d = task.get();
    System.out.println("計算結果是:"+d);
    
    //用同一個 FutureTask 再起一個線程
    Thread thread2 = new Thread(task);
    thread2.start();
}
}

class MyCallable implements Callable<Double>{

    @Override
    public Double call() {
         double d = 0;
         try {
             System.out.println("異步計算開始.......");
              d = Math.random()*10;
             d += 1000;
            Thread.sleep(2000);
             System.out.println("異步計算結束.......");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return d;
    }
}

運行結果:

異步計算開始.......
主線程等待計算結果...
異步計算結束.......
計算結果是:1002.7806590582911


除了實現Future、Runnable外,此類還提供了幾個protected方法,用於擴展此類

protected void done()
當此任務轉換到狀態 isDone(不管是正常地還是通過取消)時,調用受保護的方法。默認實現不執行任何操作。
protected void set(V v)
除非已經設置了此 Future 或已將其取消,否則將其結果設置為給定的值。在計算成功完成時通過 run 方法內部調用此方法。
protected void setException(Throwable t)
除非已經設置了此 Future 或已將其取消,否則它將報告一個 ExecutionException,並將給定的 throwable 作為其原因。在計算失敗時通過 run 方法內部調用此方法。
protected boolean runAndReset()
執行計算而不設置其結果,然後將此 Future 重置為初始狀態,如果計算遇到異常或已取消,則該操作失敗。本操作被設計用於那些本質上要執行多次的任務。

Executor框架(七)Future 接口、FutureTask類