Future三重奏第一章:Future設計模式及代碼示例

Future系列文章

Future三重奏第一章:Future設計模式及代碼示例
Future三重奏第二章:FutureTask源碼解析

Future模式的作用

去除等待主函數執行某項耗時操作的等待時間,在執行主函數耗時業務操作的時候,及時返回一個數據,繼續主函數剩下的業務,當需要獲取之前耗時操作的結果的時候在進行獲取

其本質則是在維持主業務順利進行的同時,異步的執行主業務中的耗時分業務,使得原本需要進行等待的時間可以處理其他的業務

###實際業務場景:
在開具電子發票的業務中,當我們申請開電子發票的時候,電子發票並不會立即開票成功,而是需要調取第三方接口,第三方接口在返回告訴我們是否開具成功,這時候需要等待一段時間才能得到開票結果,在等待第三方返回結果的同時,這個時候我們還有其他別的業務要進行處理返回,不可能一直等待第三方返回的數據,這時候我們就可以採用future模式,將該方法改爲異步處理,在等待數據返回的時候進行其他業務的處理

future模式核心類作用

此處通過幾個簡單的類來展示future模式的思路和運行方式
Main類:系統啓動類,調用Client類發出業務請求
Client類:該類在接收到構造並返回FutureData類,返回的FutureData類是一個虛假的對象,或者說並不是一個擁有實際數據的對象,Client的核心在於構建一個新的線程去執行RealData類,該類是處理耗時的業務類
Data:獲取實際數據的接口,futureData類和realData類需要實現該接口
FutureData類:及時返回調用類,內部封裝了實際數據,可通過該類獲取實際的業務數據
RealData:實際的業務處理類,耗時較長

future模式示例代碼

Main類

發起請求,構建執行了Client類,返回了Data對象,並在最後調用了data對象實際獲取到的數據

public class Main {

    public static void main(String args[]){
        Client client=new Client();

        //調用client發送請求
        Data data=client.request("Hello Future!");

        System.out.println("請求完畢!");

        try {
            //模擬處理其他業務
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //調用實際返回的數據
        System.out.println("真實數據:" + data.getResult());

    }
}

Data接口

Main類中實際返回Data對象,該接口提供獲取數據的方法

public interface Data {

    String getResult();
}

Client類

在主類中構建的Client類,並返回futureData對象,另一方面通過該類生成線程發出異步請求,新線程中執行業務類,並返回計算結果,將計算結果封裝進futureData對象中

public class Client {

    public Data request(String param){

        //立即返回futureData
        FutureData futureData=new FutureData();

        //需要啓動一個新線程
        //開啓ClientThread線程裝配realData
        new Thread(() -> {
            //裝配realData
            //RealData爲業務類,傳遞相關參數過去
            RealData realData=new RealData(param);

            //獲取到數據後將數據封裝進實體類中
            futureData.setRealData(realData);

        }).start();
        return futureData;
    }
}

RealData類

實際業務類,該類主要是執行業務方法並得到計算結果,並提供獲取數據的方法

public class RealData implements Data{

    private String result;//封裝實際數據


    /**
     * 獲取計算結果方法
     * @return
     */
    @Override
    public String getResult() {
        return result;
    }

    public RealData(String param){
        StringBuffer sb=new StringBuffer();

        sb.append(param);

        //模擬業務執行
        //此處通過線程睡眠的方式
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //獲取真實數據result,等待再次獲取數據
        result=sb.toString();
    }

}

FutureData類

在client的調用中,會首先返回一個空的futuredata對象,然後啓動一個新的線程去執行業務類獲取數據,在獲取數據後,會將獲取的數據封裝進futuredata類中,所以,futuredata類相應的提供了封裝實際數據的方法。當你需要獲取實際數據當時候,如果尚未獲取數據成功,則進入等待隊列

public class FutureData implements Data {


    private RealData realData;

    private boolean isReady=false;//如果已經獲取數據此處爲true

    private ReentrantLock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();

    /**
     * 獲取實際數據
     * @return
     */
    @Override
    public String getResult()
    {
        //如果尚未成功獲取數據,則當前線程加入等待隊列
        while (!isReady){
            try {
                lock.lock();
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
        return realData.getResult();
    }

    public void setRealData(RealData realData){
        lock.lock();
        if (isReady){
            return;
        }

        //裝載實際數據對象
        this.realData = realData;
        isReady = true;
        condition.signal();
        lock.unlock();
    }
}

以上就是future設計模式的簡單實現,future模式在線程池的實現中有很大的體現,在第二章中我會詳細介紹jdk中futuretask的詳細實現,在線程池模塊中也會對futureTask的使用作出詳細介紹

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章