1. 程式人生 > >Java併發:Callable與Future

Java併發:Callable與Future

Callable

Runnable 封裝一個非同步執行的任務,可以把它想象成為一個沒有引數和返回值的非同步方法。

Runnable runnable = new Runnable() {
    @Override
    public void run() {

    }
};

runnable.run();

Callable 和 Runnable 類似,但是有返回值,Callable 介面只有一個方法 call。

public interface Callable<V>{
    V call() throw Exception;
}
Callable<Integer> callable = new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        
        return null;
    }
};

Integer result = callable.call();

引數型別是返回的型別,例如 Callable<Integer> 表示一個最終返回 Integer 物件的非同步計算。

可以像上例一樣直接執行 call() 方法,然後獲取執行結果,但是,除了可以獲取最終結果之外,你不能對它進行任何操作或干預。

若想監控這個計算是否執行完畢,或者試圖中斷它,有以下兩種方案:

1.藉助FutureTask包裝器

將 Callable 例項作為構造引數提交給一個 FutureTask 例項,然後呼叫 FutureTask 例項的 run() 方法

FutureTask<Integer> task = new FutureTask<>(callable);

task.run();

在 run() 方法內部,callable 物件的 call() 方法將會被呼叫,計算完成後,FutureTask 會將結果儲存下來,可以通過 get 方法獲取計算結果

public V get()
public V get(long timeout, TimeUnit unit)

第一個 get 方法的呼叫被阻塞,直到計算完成。

第二個 get 方法會等待指定的時間,若時間之內計算仍然沒有完成,則丟擲 TimeoutException 異常。

如果計算被中斷,兩個 get 方法都將丟擲 InterruptedException 異常。

2.將Callable提交給執行緒池

利用 Executors 類的工廠方法獲取執行緒池(請參考我的另一篇文章:Executor 執行器),然後呼叫 submit 方法提交計算任務。

ExecutorService executor = Executors.newCachedThreadPool();

Future<Integer> future = executor.submit(callable);

submit 方法將返回一個 Future 的 例項物件,該物件包含了任務的計算結果,實際上,在上一個方案中的 FutureTask 類即是 Future 的一個實現:

FutureTask 實現了 RunnableFuture 介面

public class FutureTask<V> implements RunnableFuture<V>

 而 RunnableFuture 介面繼承於 Runnable, Future 介面

public interface RunnableFuture<V> extends Runnable, Future<V> 

 

Future

Future 介面共包含五個抽象方法:

  1. cancel(boolean mayInterrupt) :可以用此方法取消計算,如果計算還沒有開始,它將被取消且不再開始;若計算已經處於執行之中,且 mayInterrupt 引數為 true,則計算將被中斷:這將導致對這個任務 get 方法的呼叫丟擲 InterruptedException 異常。
  2. isCancelled() :如果該計算在完成之前被取消則返回 true。
  3. isDone() :如果任務已經完成則返回 ture (正常結束,被取消,丟擲異常都視為任務完成)
  4. get() :獲取計算結果,此方法阻塞呼叫,直到計算完成。
  5. get(long timeout, TimeUnit unit) :獲取計算結果,如果計算已完成則直接返回,若沒完成則等待指定的時間,時間之內計算仍沒有完成,則丟擲 TimeoutException 異常
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get();
    V get(long timeout, TimeUnit unit)