Future
January 13, 2022你可能有過這類對話的經驗:「老闆,我要一份蚵仔煎,待會來拿!」這也描述了 Future 的概念。
未來的結果
Future 就是讓你在未來取得結果。可以將想執行的工作交給 Future,Future 會使用另一執行緒來進行工作,你就可以先忙別的事去,過些時候,再從 Future 取得結果。
如果未來某個時間點,結果尚未準備好,就想取得呢?這就要看需求了,看是要等待,或者是指定等待時間,或者是拋出例外,也可以讓 Future 物件提供查詢方法,讓客戶端查詢結果已備妥後再拿取。
來看看 Future 的基本實作方式:
class Future<T> implements Runnable {
private Callable<T> callable;
private T r;
Future(Callable<T> callable) {
this.callable = callable;
}
boolean isDone() {
return r != null;
}
synchronized T get() throws InterruptedException {
while(r == null) {
wait();
}
return r;
}
public void run() {
try {
synchronized(this) {
r = callable.call();
notify();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static <T> Future<T> submit(Callable<T> callable) {
var future = new Future<>(callable);
new Thread(future).start();
return future;
}
}
這邊的 get
實作,是有結果才會傳回,沒有結果時進入等待,為了隱藏執行緒的建立細節,簡單地在 Future
上設計了 static
的 submit
方法,其中直接 new
建立 Thread
,實際上,也可以透過執行緒池之類的方式來取得執行緒。
就以上這個 Future
實作而言,可以如下使用:
static long fibonacci(long n) {
if(n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) throws InterruptedException {
var future = Future.submit(() -> fibonacci(30));
out.println("老闆,我要第 30 個費式數,待會來拿...");
while(!future.isDone()) {
out.println("忙別的事去...");
}
out.printf("第 30 個費式數:%d%n", future.get());
}
Java 的 Future
Java 的並行 API 中,規範了 java.util.concurrent.Future
等介面,例如 java.util.concurrent.FutureTask
是 Future
的實作類別,建構時可傳入 Callable
實作物件指定的執行的內容。
var future = new FutureTask<>(() -> fibonacci(30));
new Thread(future).start();
out.println("老闆,我要第 30 個費式數,待會來拿...");
while(!future.isDone()) {
out.println("忙別的事去...");
}
out.printf("第 30 個費式數:%d%n", future.get());
若不想自行建立、管理 Thread
,可以透過 ExecutorService
:
var service = Executors.newCachedThreadPool();
var future = service.submit(() -> fibonacci(30));
out.println("老闆,我要第 30 個費式數,待會來拿...");
while(!future.isDone()) {
out.println("忙別的事去...");
}
out.printf("第 30 個費式數:%d%n", future.get());
Executors.newCachedThreadPool
會建立 ExecutorService
的實例,具有執行緒池的功能,ExecutorService
定義了 submit
方法傳回 Future
實例。