java中Future的使用
Future是java 1.5引入的一個interface,可以方便的用於異步結果的獲取。 本文將會通過具體的例子講解如何使用Future。
創建Future
正如上面所說,Future代表的是異步執行的結果,意思是當異步執行結束之后,返回的結果將會保存在Future中。
那么我們什么時候會用到Future呢? 一般來說,當我們執行一個長時間運行的任務時,使用Future就可以讓我們暫時去處理其他的任務,等長任務執行完畢再返回其結果。
經常會使用到Future的場景有:1. 計算密集場景。2. 處理大數據量。3. 遠程方法調用等。
接下來我們將會使用ExecutorService來創建一個Future。
<T> Future<T> submit(Callable<T> task);
上面是ExecutorService中定義的一個submit方法,它接收一個Callable參數,並返回一個Future。
我們用一個線程來計算一個平方運算:
private ExecutorService executor
= Executors.newSingleThreadExecutor();
public Future<Integer> calculate(Integer input) {
return executor.submit(() -> {
System.out.println("Calculating..."+ input);
Thread.sleep(1000);
return input * input;
});
}
submit需要接受一個Callable參數,Callable需要實現一個call方法,並返回結果。這里我們使用lamaba表達式來簡化這一個流程。
從Future獲取結果
上面我們創建好了Future,接下來我們看一下怎么獲取到Future的值。
FutureUsage futureUsage=new FutureUsage();
Future<Integer> futureOne = futureUsage.calculate(20);
while(!futureOne.isDone()) {
System.out.println("Calculating...");
Thread.sleep(300);
}
Integer result = futureOne.get();
首先我們通過Future.isDone() 來判斷這個異步操作是否執行完畢,如果完畢我們就可以直接調用futureOne.get()來獲得Futre的結果。
這里futureOne.get()是一個阻塞操作,會一直等待異步執行完畢才返回結果。
如果我們不想等待,future提供了一個帶時間的方法:
Integer result = futureOne.get(500, TimeUnit.MILLISECONDS);
如果在等待時間結束的時候,Future還有返回,則會拋出一個TimeoutException。
取消Future
如果我們提交了一個異步程序,但是想取消它, 則可以這樣:
uture<Integer> futureTwo = futureUsage.calculate(4);
boolean canceled = futureTwo.cancel(true);
Future.cancel(boolean) 傳入一個boolean參數,來選擇是否中斷正在運行的task。
如果我們cancel之后,再次調用get()方法,則會拋出CancellationException。
多線程環境中運行
如果有兩個計算任務,先看下在單線程下運行的結果。
Future<Integer> future1 = futureUsage.calculate(10);
Future<Integer> future2 = futureUsage.calculate(100);
while (!(future1.isDone() && future2.isDone())) {
System.out.println(
String.format(
"future1 is %s and future2 is %s",
future1.isDone() ? "done" : "not done",
future2.isDone() ? "done" : "not done"
)
);
Thread.sleep(300);
}
Integer result1 = future1.get();
Integer result2 = future2.get();
System.out.println(result1 + " and " + result2);
因為我們通過Executors.newSingleThreadExecutor()來創建的單線程池。所以運行結果如下:
Calculating...10
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
Calculating...100
future1 is done and future2 is not done
future1 is done and future2 is not done
future1 is done and future2 is not done
100 and 10000
如果我們使用Executors.newFixedThreadPool(2)來創建一個多線程池,則可以得到如下的結果:
calculating...10
calculating...100
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
future1 is not done and future2 is not done
100 and 10000
本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/future
更多教程請參考 flydean的博客