1. 程式人生 > >Future三重奏第一章:Future設計模式及程式碼示例

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

Future系列文章

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的使用作出詳細介紹