FutureTask 有點相似Runnable,均可以經過Thread來啓動,不過FutureTask能夠返回執行完畢的數據,而且FutureTask的get方法支持阻塞。java
因爲:FutureTask能夠返回執行完畢的數據,而且FutureTask的get方法支持阻塞這兩個特性,咱們能夠用來預先加載一些可能用到資源,而後要用的時候,調用get方法獲取(若是資源加載完,直接返回;不然繼續等待其加載完成)。網絡
下面經過兩個例子來介紹下:異步
一、使用FutureTask來預加載稍後要用的的數據。ide
package com.jhaso.concurrency.futuretask; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * 使用FutureTask來提早加載稍後要用到的數據 * * @author zhy * */ public class PreLoaderUseFutureTask { /** * 建立一個FutureTask用來加載資源 */ private final FutureTask<String> futureTask = new FutureTask<String>( new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(3000); return "加載資源須要3秒"; } }); public final Thread thread = new Thread(futureTask); public void start() { thread.start(); } /** * 獲取資源 * * @return * @throws ExecutionException * @throws InterruptedException */ public String getRes() throws InterruptedException, ExecutionException { return futureTask.get();//加載完畢直接返回,不然等待加載完畢 } public static void main(String[] args) throws InterruptedException, ExecutionException { PreLoaderUseFutureTask task = new PreLoaderUseFutureTask(); /** * 開啓預加載資源 */ task.start(); // 用戶在真正須要加載資源前進行了其餘操做了2秒 Thread.sleep(2000); /** * 獲取資源 */ System.out.println(System.currentTimeMillis() + ":開始加載資源"); String res = task.getRes(); System.out.println(res); System.out.println(System.currentTimeMillis() + ":加載資源結束"); } }
運行結果:this
1400902789275:開始加載資源 加載資源須要3秒 1400902790275:加載資源結束
能夠看到,原本加載資源的時間須要3秒,如今只花費了1秒,若是用戶其餘操做時間更長,則可直接返回,極大增長了用戶體驗。線程
二、看下Future的API資源
能夠看到Future的API,仍是比簡單的,見名知意的感受,get( long , TimeUnit )還能支持,設置最大等待時間,好比某個操做耗時太長,就能夠取消了。get
三、FutureTask模擬,用戶在線觀看電子書的預加載功能it
用戶觀看當前頁時,後臺預先把下一頁加載好,這樣能夠大幅度提升用戶的體驗,不須要每一頁都等待加載,用戶會以爲此電子書軟件很流暢,哈哈,用戶以爲好,纔是真的好。io
package com.zhy.concurrency.futuretask; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * 使用FutureTask模擬預加載下一頁圖書的內容 * * @author zhy * */ public class BookInstance { /** * 當前的頁碼 */ private volatile int currentPage = 1; /** * 異步的任務獲取當前頁的內容 */ FutureTask<String> futureTask = new FutureTask<String>( new Callable<String>() { @Override public String call() throws Exception { return loadDataFromNet(); } }); /** * 實例化一本書,並傳入當前讀到的頁碼 * * @param currentPage */ public BookInstance(int currentPage) { this.currentPage = currentPage; /** * 直接啓動線程獲取當前頁碼內容 */ Thread thread = new Thread(futureTask); thread.start(); } /** * 獲取當前頁的內容 * * @return * @throws InterruptedException * @throws ExecutionException */ public String getCurrentPageContent() throws InterruptedException, ExecutionException { String con = futureTask.get(); this.currentPage = currentPage + 1; Thread thread = new Thread(futureTask = new FutureTask<String>( new Callable<String>() { @Override public String call() throws Exception { return loadDataFromNet(); } })); thread.start(); return con; } /** * 根據頁碼從網絡抓取數據 * * @return * @throws InterruptedException */ private String loadDataFromNet() throws InterruptedException { Thread.sleep(1000); return "Page " + this.currentPage + " : the content ...."; } public static void main(String[] args) throws InterruptedException, ExecutionException { BookInstance instance = new BookInstance(1); for (int i = 0; i < 10; i++) { long start = System.currentTimeMillis(); String content = instance.getCurrentPageContent(); System.out.println("[1秒閱讀時間]read:" + content); Thread.sleep(1000); System.out.println(System.currentTimeMillis() - start); } } }
輸出結果:
[1秒閱讀時間]read:Page 1 : the content .... 2001 [1秒閱讀時間]read:Page 2 : the content .... 1000 [1秒閱讀時間]read:Page 3 : the content .... 1001 [1秒閱讀時間]read:Page 4 : the content .... 1000 [1秒閱讀時間]read:Page 5 : the content .... 1001
能夠看到,除了第一次觀看當前頁須要等待網絡加載數據的過程(輸出的:2001,1000是加載耗時,1000是用戶閱讀時間),接下來的頁面都是瞬間返回(輸出的1000是用戶閱讀時間),徹底不須要等待。
代碼都是爲了講解FutureTask的應用場景,,,請勿直接在項目中使用。