Future模式有點相似於網上購物,在你購買商品,訂單生效以後,你能夠去作本身的事情,等待商家經過快遞給你送貨上門。Future模式就是,當某一程序提交請求,指望獲得一個答覆。可是可能服務器程序對這個請求的處理比較慢,所以不可能立刻收到答覆。可是,在傳統的單線程環境下,調用函數是同步的,它必須等到服務程序返回結果,才能繼續進行其餘處理。而Future模式下,調用方法是異步的,本來等待返回的時間段,在主調函數中,則能夠處理其餘的任務。傳統的串行程序釣友以下圖所示:服務器
Future模式的處理流程:併發
從圖中能夠看出,雖然call()自己是一個須要很長世間處理的程序。可是,服務程序不等數據處理完就馬上返回客戶端一個僞數據(相似於商品訂單,你購物須要的是商品自己),實現Future模式的客戶端在拿到這個返回結果後,並不急於對它進行處理,而是去調用其它的業務邏輯,使call()方法有充分的時間去處理完成,這也是Future模式的精髓所在。在處理完其餘業務邏輯後,最後再使用處理比較費時的Future數據。這個在處理過程當中,就不存在無謂的等待,充分利用了時間,從而提高了系統的響應和性能。app
下面以一個經典的Future實現爲例,簡單介紹下Future的核心實現。代碼中Date接口:返回數據的接口;FutureDate類:實現Date接口,構造很快,返回一個虛擬的僞數據,須要裝配RealDate;RealDate類:實現Date接口,返回真實數據,構造比較慢;Client:返回Date數據,當即返回FutureDate數據,並開啓線程裝配RealDate數據。異步
代碼實現:ide
1 public interface Data { 2 public String getResult(); 3 } 4 5 public class FutureData implements Data { 6 7 protected RealData realData = null; 8 9 protected boolean isReady = false; 10 //進行同步控制 11 public synchronized void setResult(RealData realData){ 12 if(isReady){ 13 return; 14 } 15 System.out.println("FutureData.setResult()"); 16 this.realData=realData; 17 isReady = true; 18 notifyAll(); 19 20 } 21 //實際調用返回RealDate的數據 22 @Override 23 public synchronized String getResult() { 24 while(!isReady){ 25 try { 26 wait(); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 } 31 System.out.println("FutureData.getResult()"); 32 return realData.result; 33 } 34 35 public class RealData implements Data{ 36 37 protected final String result; 38 39 public RealData(String s) { 40 StringBuffer sb = new StringBuffer(); 41 42 for (int i = 0; i < 10; i++) { 43 sb.append(s); 44 try { 45 //模擬構造時間比較長 46 Thread.sleep(1000); 47 } catch (InterruptedException e) { 48 49 } 50 51 } 52 53 System.out.println("RealData.RealData()"); 54 result = sb.toString(); 55 } 56 57 public class Client { 58 public Data request(final String queryStr){ 59 //返回僞數據 60 final FutureData futureData = new FutureData(); 61 //開啓線程構造真實數據 62 new Thread(){ 63 public void run(){ 64 RealData realData = new RealData(queryStr); 65 futureData.setResult(realData); 66 } 67 }.start(); 68 //返回僞數據,等待真實數據加載 69 return futureData; 70 } 71 }
啓動系統,調用Client發送請求:函數
1 public class TestMain { 2 public static void main(String[] args) { 3 Data data = new Client().request("123456"); 4 System.out.println(data); 5 System.out.println(data.getResult()); 6 } 7 }
能夠看出,FutureDate是Future模式實現的關鍵,它實際是真實數據RealDate的代理,封裝了獲取RealDate的等待過程。性能
在JDK的內置併發包中,就已經內置了一種Future的實現,提供了更加豐富的線程控制,其基本用意和核心理念與上面實現代碼一致。this
在JDK中的Future模式中,最重要的是FutureTask類,它實現了Runnable接口,能夠做爲單獨的線程運行。在其run()方法中,經過Sync內部類,調用Callable接口,並維護Callable接口的返回對象。當使用FutureTask.get()時,將返回Callable接口的返回對象。FutureTask還能夠對任務自己進行其餘控制操做。spa
利用Callable接口實現上述例子相同的操做:線程
RealDate類的實現:
1 public class Real1Data implements Callable<String>{ 2 3 private String reaString; 4 5 public Real1Data(String reaString) { 6 super(); 7 this.reaString = reaString; 8 } 9 10 11 @Override 12 public String call() throws Exception { 13 14 StringBuffer sb = new StringBuffer(); 15 16 for (int i = 0; i < 10; i++) { 17 sb.append(reaString); 18 try { 19 Thread.sleep(100); 20 } catch (InterruptedException e) { 21 // TODO: handle exception 22 } 23 24 } 25 26 return sb.toString(); 27 } 28 29 }
Client代碼實現:
1 public class Test1Main { 2 public static void main(String[] args) throws InterruptedException, ExecutionException { 3 FutureTask<String> future = new FutureTask<>(new Real1Data("1111")); 4 5 ExecutorService exe = Executors.newFixedThreadPool(1); 6 7 exe.submit(future); 8 9 System.out.println("FutureTask"); 10 11 try { 12 Thread.sleep(1000); 13 } catch (InterruptedException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 18 System.out.println("FutureTask"+future.get()); 19 } 20 }
能夠看出RealDate的構造速度很快,其核心代碼邏輯放在了call()中實現,再也不須要Date和FutureDate,直接經過RealDate來構造FutureTask,將其做爲單獨的線程運行。在提交請求後,執行其餘業務邏輯,作好經過FututeTask.get()方法,獲得RealDate的執行結果。
Futute模式核心在於去除了主調用函數的等待時間,並使得本來須要等待的時間能夠充分利用來處理其餘業務邏輯,充分的利用了系統資源。