1. 程式人生 > >Future模式模擬

Future模式模擬

err data 很快 處理 image scrip 通知 51cto ted

Future模式是一種非常常見的設計模式,其核心思想就是異步調用。

1. Future模式的主要參與者

參與者 作用 備註
Main 系統啟動,調用client發出請求 可以看做是一個應用
client 用於返回Data對象,立即返回FutureData,並開啟一個線程裝配RealData
Data 返回數據的接口
FutureData FutureData實現了Data接口,構造很快,是一個虛擬數據,需要裝配RealData真實數據 也可以看做是構造一個空的Data對象,按字面意思來看就是將來的數據,還沒有...,當客戶端需要使用數據時需要設置成RealData對象
RealData 真實數據,起構造可能會比較慢,RealData也實現了Data接口 這個數據才是Main應用需要的

2. Future模式流程圖如下:

技術分享圖片

3. Future模式的簡單實現

3.1 核心接口Data
/**
 * Created with IntelliJ IDEA.
 * User: 
 * Date: 2018/12/29
 * Time: 下午6:47
 * Description: Data接口有兩個重要的實現,FutureData和RealData,RealData代表的是真實數據,FutureData是真實數據的代理或者說是包裝
 */
public interface Data {
    String getResult();
}
/**
 * Created with IntelliJ IDEA.
 * User: 
 * Date: 2018/12/29
 * Time: 下午6:44
 * Description: 實現Data接口,其功能是對RealData進行包裝、代理,在FutureClient請求Data數據時,將立即返回一個包裝好的虛擬數據(RealData的虛擬數據)
 */
public class FutureData implements Data {

    //既然FutureData是RealData對象的包裝,那麽久應該有一個對象的引用
    private RealData realData = null;

    //標註真實數據是否準備好
    private boolean isReady = false;

    //取數據時,如果RealData還沒註入數據,則將阻塞等待
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void setRealData(RealData realData) {
        while (isReady) {
            //數據已經準備好,直接退出
            return;
        }
        lock.lock();
        try {
            this.realData = realData;
            this.isReady = true;
            //數據已經準備,通知阻塞在getResult()上的請求
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 獲取真實數據,如果RealData代理對象沒有準備好數據,則阻塞
     *
     * @return
     */
    public String getResult() {
        lock.lock();
        try {
            while (!isReady) {
                //釋放鎖,同時阻塞
                condition.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return realData.result;
    }
}
/**
 * Created with IntelliJ IDEA.
 * User: zhouyonggui
 * Date: 2018/12/29
 * Time: 下午6:54
 * Description: RealData是最終需要使用的數據,需要返回給FutureData
 */
public class RealData implements Data {
    protected String result = null;

    /**
     * 在這個過程中,模擬數據包裝
     *
     * @return
     */
    public RealData(String param) {
        StringBuffer sb = new StringBuffer();
        //假設需要很長時間的業務處理
        for (int i = 0; i < 10; i++) {
            sb.append(param);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        result = sb.toString();
    }

    public String getResult() {
        return result;
    }
}

接下來就是client,內部主要實現了FutureData,並開啟一個線程去構造RealData。在接受請求後,先返回一個FutureData對象,此時FutureData內部並沒有真實數據,在需要使用數據時需要等待RealData構造完成,此時如果數據尚未準備好,則將阻塞直到有數據返回。

/**
 * Created with IntelliJ IDEA.
 * User: zyg
 * Date: 2019/1/2
 * Time: 下午9:12
 * Description:FUture客戶端主要負責獲取FutureData,並異步起一個線程,構造RealData
 */
public class Client {
    public Data request(final String queryStr) {
        final FutureData future = new FutureData();
        new Thread(new Runnable() {
            public void run() {
                RealData realData = new RealData(queryStr);
                future.setRealData(realData);
            }
        }).start();
        return future;
    }
}

最後是我們的Main應用,她主要是負責調用client發起請求,並消費返回的數據。

/**
 * Created with IntelliJ IDEA.
 * User: zyg
 * Date: 2019/1/2
 * Time: 下午9:21
 * Description:
 */
public class Main {
    public static void main(String[] args) {
        Client client = new Client();
        //客戶端發起請求
        Data data = client.request("楊冪");
        System.out.println("客戶端請求完畢!");
        //模擬其他業務
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //使用真實數據
        System.out.println("數據=" + data.getResult());
    }
}

Future模式模擬