在傳統的多線程實現方式中(繼承Thread和實現Runnable)沒法直接獲取線程執行的返回結果,若是須要獲取執行結果,就必須經過共享變量或者使用線程通訊的方式來達到效果,這樣使用起來就比較麻煩。java
從Java 1.5開始,java.util.concurrent包中提供了 Callable和 Future兩個接口,經過它們就能夠在任務執行完畢以後獲得任務執行結果。程序員
Callable與Runnable的功能大體類似,Callable中有一個call()函數,可是call()函數有返回值,而Runnable的run()函數不能將結果返回給客戶程序。多線程
Executor就是Runnable和Callable的調度容器,Future就是對於具體的Runnable或者Callable任務的執行結果進行框架
取消、查詢是否完成、獲取結果、設置結果操做。get方法會阻塞,直到任務返回結果。dom
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
也就是說Future提供了三種功能:異步
FutureTask是爲了彌補Thread的不足而設計的,它可讓程序員準確地知道線程何時執行完成並得到到線程執行完成後返回的結果(若是有須要)。ide
FutureTask是一種能夠取消的異步的計算任務。它的計算是經過Callable實現的,它等價於能夠攜帶結果的Runnable,而且有三個狀態:等待、運行和完成。完成包括全部計算以任意的方式結束,包括正常結束、取消和異常。函數
Executor框架利用FutureTask來完成異步任務,並能夠用來進行任何潛在的耗時的計算。通常FutureTask多用於耗時的計算,主線程能夠在完成本身的任務後,再去獲取結果。測試
FutureTask多用於耗時的計算,主線程能夠在完成本身的任務後,再去獲取結果。線程
Example1:
package cn.com.example.concurrent.future; import java.util.concurrent.*; /** * Created by Jack on 2017/1/24. */ public class RunnableFutureTask { /** * ExecutorService */ static ExecutorService mExecutor = Executors.newSingleThreadExecutor(); /** * @param args */ public static void main(String[] args) { runnableDemo(); futureDemo(); } /** * runnable, 無返回值 */ static void runnableDemo() { new Thread(new Runnable() { @Override public void run() { System.out.println("runnable demo : " + fibc(20)); } }).start(); } /** * 其中Runnable實現的是void run()方法,無返回值;Callable實現的是 V * call()方法,而且能夠返回執行結果。其中Runnable能夠提交給Thread來包裝下 * ,直接啓動一個線程來執行,而Callable則通常都是提交給ExecuteService來執行。 */ static void futureDemo() { try { /** * 提交runnable則沒有返回值, future沒有數據 */ Future<?> result = mExecutor.submit(new Runnable() { @Override public void run() { fibc(20); } }); System.out.println("future result from runnable : " + result.get()); /** * 提交Callable, 有返回值, future中可以獲取返回值 */ Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { return fibc(20); } }); System.out.println("future result from callable : " + result2.get()); /** * FutureTask則是一個RunnableFuture<V>,即實現了Runnbale又實現了Futrue<V>這兩個接口, * 另外它還能夠包裝Runnable(實際上會轉換爲Callable)和Callable * <V>,因此通常來說是一個符合體了,它能夠經過Thread包裝來直接執行,也能夠提交給ExecuteService來執行 * ,而且還能夠經過v get()返回執行結果,在線程體沒有執行完成的時候,主線程一直阻塞等待,執行完則直接返回結果。 */ FutureTask<Integer> futureTask = new FutureTask<Integer>( new Callable<Integer>() { @Override public Integer call() throws Exception { return fibc(20); } }); // 提交futureTask mExecutor.submit(futureTask); System.out.println("future result from futureTask : " + futureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } /** * 效率底下的斐波那契數列, 耗時的操做 * * @param num * @return */ static int fibc(int num) { if (num == 0) { return 0; } if (num == 1) { return 1; } return fibc(num - 1) + fibc(num - 2); } }
結果:
runnable demo : 6765 future result from runnable : null future result from callable : 6765 future result from futureTask : 6765
Example2:
package cn.com.example.concurrent.future; import java.util.Random; import java.util.concurrent.*; /** * Created by Jack on 2017/1/24. */ public class RunnableFutureTask { public static void main(String[] args) { // 初始化一個Callable對象和FutureTask對象 Callable pAccount = new PrivateAccount(); FutureTask futureTask = new FutureTask(pAccount); // 使用futureTask建立一個線程 Thread pAccountThread = new Thread(futureTask); System.out.println("futureTask線程如今開始啓動,啓動時間爲:" + System.nanoTime()); pAccountThread.start(); System.out.println("主線程開始執行其餘任務"); // 從其餘帳戶獲取總金額 int totalMoney = new Random().nextInt(100000); System.out.println("如今你在其餘帳戶中的總金額爲" + totalMoney); System.out.println("等待私有帳戶總金額統計完畢..."); // 測試後臺的計算線程是否完成,若是未完成則等待 while (!futureTask.isDone()) { try { Thread.sleep(500); System.out.println("私有帳戶計算未完成繼續等待..."); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("futureTask線程計算完畢,此時時間爲" + System.nanoTime()); Integer privateAccountMoney = null; try { privateAccountMoney = (Integer) futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("您如今的總金額爲:" + totalMoney + privateAccountMoney.intValue()); } } class PrivateAccount implements Callable { Integer totalMoney; @Override public Object call() throws Exception { Thread.sleep(5000); totalMoney = new Integer(new Random().nextInt(10000)); System.out.println("您當前有" + totalMoney + "在您的私有帳戶中"); return totalMoney; } }
結果:
futureTask線程如今開始啓動,啓動時間爲:88171383410225 主線程開始執行其餘任務 如今你在其餘帳戶中的總金額爲2838 等待私有帳戶總金額統計完畢... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 私有帳戶計算未完成繼續等待... 您當前有9238在您的私有帳戶中 私有帳戶計算未完成繼續等待... futureTask線程計算完畢,此時時間爲88176389195218 您如今的總金額爲:28389238