Future異步調用

轉載自http://eyesmore.iteye.com/blog/243648javascript

在多線程交互的中2,常常有一個線程須要獲得另個一線程的計算結果,咱們經常使用的是Future異步模式來加以解決。
Future顧名思意,有點像期貨市場的「期權」,是「對將來的一種憑證」,例如當咱們買了某個房地產開發商的期房,交錢以後,開發商會給咱們一個憑證(期權),這個憑證告訴咱們等明年某個時候拿這個憑證就能夠拿到咱們所須要的房子,可是如今房子還沒建好。市場上之因此有「期貨」,也正因爲有這種需求,纔有這種供給。java

 

這種應用在GUI上用的比較多,在設計模式中通常稱爲「虛擬代理模式」。設計模式

 

例如:如今有個這樣的需求,Client向Server提交一個Request(int count,char c),但願獲取一個由count個字符c構造出來的字符串。好比發送Request(10,'K'),那麼反饋字符串「KKKKKKKKKK」,可是咱們假設這個生成字符串的過程很費時間。多線程

 

因而,爲了獲取比較好的交互性,咱們的Server收到請求後,先構造一個FutureData,並把這個所謂的「期權(將來憑證)」反饋給Client;於此同時,經過另外一個併發線程去構造一個真正的字符串RealData,並在構造完畢後,RealData給FutureData報告一個消息,說數據(期房)已經準備好了,此時Client能夠經過期權拿到期房,可是假如咱們的Client比較着急,還沒等房子假好的時,就想要房子,怎麼辦呢?這個時候咱們能夠阻塞Client所在的線程,讓Client等待,直到最後RealData通知FutureData說房子好了,才返回。併發

這裏的要點:異步

(1)Server先給Client一個「期權」,同時開一個線程去幹活建房子(將來的「現房」);ide

(2)當「現房」RealData準備好了的時候,如何告訴FutureData說已經準備好了。(本處採用「回調過程」(借用觀察者模式,來實現回調))this

(3)若是客戶比較着急,現房還沒準備好的時候,就要取房,怎麼辦?  本處採用「阻塞」。url

 

Data(公共數據接口)spa

 

Java代碼 複製代碼  收藏代碼
  1. package com.umpay.future;   
  2.   
  3. public interface Data {   
  4.     public abstract String getContent();   
  5. }  

 

FutureData(期權)

 

Java代碼 複製代碼  收藏代碼
  1. package com.umpay.future.extend;   
  2.   
  3. import java.util.Observable;   
  4. import java.util.Observer;   
  5.   
  6. import com.umpay.future.Data;   
  7.   
  8. public class FutureData2 implements Data,Observer {   
  9.   
  10.     /**   
  11.      * 存放真實數據,而且標誌真正的數據是否已經準備完畢  
  12.      * 被多線程享受  
  13.      * 若是realData2==null,表示數據還準備好  
  14.      * */  
  15.     private volatile RealData2 realData2 = null;   
  16.     /**  
  17.      * 查看真正的數據是否準備完畢  
  18.      * */  
  19.     public boolean isFinished() {   
  20.         return realData2 != null;   
  21.     }   
  22.        
  23.     /**  
  24.      * 若是數據已經準備好,則返回真正的數據;  
  25.      * 不然,阻塞調用線程,直到數據準備完畢後,才返回真實數據;  
  26.      * */  
  27.     public String getContent() {   
  28.         synchronized (mutex) {   
  29.             while(!isFinished()) {//只要數據沒有準備完畢,就阻塞調用線程   
  30.                 try {   
  31.                     mutex.wait();   
  32.                 } catch (InterruptedException e) {   
  33.                     e.printStackTrace();   
  34.                 }   
  35.             }   
  36.             return realData2.getContent();   
  37.         }   
  38.     }   
  39.   
  40.     /**  
  41.      *  當 RealData2 準備完數據後,RealData2 應該通知 FutureData2 數據準備完畢。  
  42.      *  並在輸入參數 realData 傳入真實數據,在參數 event 傳入事件(好比數據如期準備好了,或出了什麼異常)  
  43.      *  
  44.      *  @param  realData    真實的數據  
  45.      *  @param  event       事件類型  
  46.      * */  
  47.     public void update(Observable realData, Object event) {   
  48.         System.out.println("通知...."+event);   
  49.         if(!(realData instanceof RealData2)) {   
  50.             throw new IllegalArgumentException("主題的數據類型必須是RealData2");   
  51.         }   
  52.         if(!(event instanceof String)) {   
  53.             throw new IllegalArgumentException("事件的數據類型必須是String");   
  54.         }   
  55.         synchronized (mutex) {   
  56.             if(isFinished()) {   
  57.                 mutex.notifyAll();   
  58.                 return;//若是數據已經準備好了,直接返回.   
  59.             }   
  60.             if("Finished".equals(event)) {   
  61.                 realData2 = (RealData2)realData;//數據準備好了的時候,即可以通知數據準備好了   
  62.                 mutex.notifyAll();//喚醒被阻塞的線程   
  63.             }    
  64.         }   
  65.     }   
  66.   
  67.     private Object mutex = new Object();   
  68. }  

 

RealData(實際數據)

 

Java代碼 複製代碼  收藏代碼
  1. package com.umpay.future.extend;   
  2.   
  3. import java.util.Observable;   
  4.   
  5. import com.umpay.future.Data;   
  6.   
  7. public class RealData2 extends Observable implements Data {   
  8.   
  9.     private String content;   
  10.   
  11.     public RealData2() {   
  12.            
  13.     }   
  14.        
  15.     public void createRealData2(int count, char c) {   
  16.         System.out.println("        making RealData(" + count + ", " + c   
  17.                 + ") BEGIN");   
  18.         char[] buffer = new char[count];   
  19.         for (int i = 0; i < count; i++) {   
  20.             buffer[i] = c;   
  21.             try {   
  22.                 Thread.sleep(100);   
  23.             } catch (InterruptedException e) {   
  24.             }   
  25.         }   
  26.         System.out.println("        making RealData(" + count + ", " + c   
  27.                 + ") END");   
  28.         this.content = new String(buffer);   
  29.            
  30.         //真實數據準備完畢了,通知FutureData2說數據已經準備好了.   
  31.         setChanged();//必須先設置本對象的狀態發生了變化,而且通知全部的觀察者   
  32.         notifyObservers("Finished");   
  33.     }   
  34.        
  35.   
  36.     public String getContent() {   
  37.         return content;   
  38.     }   
  39. }  

 

 

服務端代碼:

 

Java代碼 複製代碼  收藏代碼
  1. package com.umpay.future.extend;   
  2.   
  3. import com.umpay.future.Data;   
  4.   
  5. public class HostServer2 {   
  6.   
  7.     public Data request(final int count, final char c) {   
  8.         System.out.println("    request(" + count + ", " + c + ") BEGIN");   
  9.   
  10.         // (1) 創建FutureData的實體   
  11.         final FutureData2 future2 = new FutureData2();   
  12.   
  13.         // (2) 爲了創建RealData的實體,啓動新的線程   
  14.         new Thread() {   
  15.             public void run() {   
  16.                 RealData2 realdata2 = new RealData2();   
  17.                 realdata2.addObserver(future2);//以便當RealData2把數據準備完畢後,經過該回調口子,通知FutureData2表示數據已經貯備好了   
  18.                 realdata2.createRealData2(count, c);   
  19.             }   
  20.         }.start();   
  21.   
  22.         System.out.println("    request(" + count + ", " + c + ") END");   
  23.   
  24.         // (3) 取回FutureData實體,做爲傳回值   
  25.         return future2;   
  26.     }   
  27.   
  28. }  

 

客戶端代碼:

 

Java代碼 複製代碼  收藏代碼
  1. package com.umpay.future;   
  2.   
  3. import com.umpay.future.extend.HostServer2;   
  4.   
  5. public class MainClient {   
  6.     public static void main(String[] args) {   
  7. //      testHostServer();   
  8.         testHostServer2();   
  9.     }   
  10.        
  11.     static void testHostServer() {   
  12.         System.out.println("main BEGIN");   
  13.         HostServer hostServer = new HostServer();   
  14.         Data data1 = hostServer.request(10'A');   
  15.         Data data2 = hostServer.request(20'B');   
  16.         Data data3 = hostServer.request(30'C');   
  17.   
  18.         System.out.println("main otherJob BEGIN");   
  19. //        try {   
  20. //            Thread.sleep(2000);   
  21. //        } catch (InterruptedException e) {   
  22. //        }   
  23.         System.out.println("main otherJob END");   
  24.   
  25.         System.out.println("data1 = " + data1.getContent());   
  26.         System.out.println("data2 = " + data2.getContent());   
  27.         System.out.println("data3 = " + data3.getContent());   
  28.         System.out.println("main END");   
  29.   
  30.     }   
  31.   
  32.     static void testHostServer2() {   
  33.         System.out.println("main BEGIN");   
  34.         HostServer2 hostServer2 = new HostServer2();   
  35.         Data data1 = hostServer2.request(10'A');   
  36.         Data data2 = hostServer2.request(20'B');   
  37.         Data data3 = hostServer2.request(30'C');   
  38.   
  39.         System.out.println("main otherJob BEGIN");   
  40. //        try {   
  41. //            Thread.sleep(2000);   
  42. //        } catch (InterruptedException e) {   
  43. //        }   
  44.         System.out.println("main otherJob END");   
  45.   
  46.         System.out.println("data1 = " + data1.getContent());   
  47.         System.out.println("data2 = " + data2.getContent());   
  48.         System.out.println("data3 = " + data3.getContent());   
  49.         System.out.println("main END");   
  50.   
  51.     }   
  52. }  
相關文章
相關標籤/搜索