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 介面共包含五個抽象方法:
- cancel(boolean mayInterrupt) :可以用此方法取消計算,如果計算還沒有開始,它將被取消且不再開始;若計算已經處於執行之中,且 mayInterrupt 引數為 true,則計算將被中斷:這將導致對這個任務 get 方法的呼叫丟擲 InterruptedException 異常。
- isCancelled() :如果該計算在完成之前被取消則返回 true。
- isDone() :如果任務已經完成則返回 ture (正常結束,被取消,丟擲異常都視為任務完成)
- get() :獲取計算結果,此方法阻塞呼叫,直到計算完成。
- 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)