Future模式

  • Future模式簡介

  Future模式有點相似於網上購物,在你購買商品,訂單生效以後,你能夠去作本身的事情,等待商家經過快遞給你送貨上門。Future模式就是,當某一程序提交請求,指望獲得一個答覆。可是可能服務器程序對這個請求的處理比較慢,所以不可能立刻收到答覆。可是,在傳統的單線程環境下,調用函數是同步的,它必須等到服務程序返回結果,才能繼續進行其餘處理。而Future模式下,調用方法是異步的,本來等待返回的時間段,在主調函數中,則能夠處理其餘的任務。傳統的串行程序釣友以下圖所示:服務器

  

  Future模式的處理流程:併發

  從圖中能夠看出,雖然call()自己是一個須要很長世間處理的程序。可是,服務程序不等數據處理完就馬上返回客戶端一個僞數據(相似於商品訂單,你購物須要的是商品自己),實現Future模式的客戶端在拿到這個返回結果後,並不急於對它進行處理,而是去調用其它的業務邏輯,使call()方法有充分的時間去處理完成,這也是Future模式的精髓所在。在處理完其餘業務邏輯後,最後再使用處理比較費時的Future數據。這個在處理過程當中,就不存在無謂的等待,充分利用了時間,從而提高了系統的響應和性能。app

  • Future模式的核心結構

  下面以一個經典的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內置實現

  在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模式核心在於去除了主調用函數的等待時間,並使得本來須要等待的時間能夠充分利用來處理其餘業務邏輯,充分的利用了系統資源。

相關文章
相關標籤/搜索