深入理解[Future模式]原理與技術

qq_42606051發表於2018-09-22

1.Future模式

Future模式和多執行緒技術密切相關,可以說是利用多執行緒技術優化程式的一個例項。

在程式設計中,當某一段程式提交了一個請求,期望得到一個答覆。但非常不幸的是,服務程式對這個請求的處理可能比較慢,比如,這個請求可能是通過網際網路、HTTP或者Web Service等並不高效的方式呼叫的。在傳統的單執行緒環境下,呼叫函式是同步的,也就是說它必須等到服務程式返回結束後,才能進行其他處理。而在Future模式下,呼叫方式改為非同步的,而原先等待返回的時間段,在主呼叫函式中,則可能用於處理其它事務。示例程式:

(1)Main方法的實現

main方法主要負責呼叫Client發起請求,並使用返回的資料:

public class Future {
    public static void main(String[] args) {
        Client client = new Client();
        Data data = client.request("name");
        System.out.println("請求完畢 "+System.currentTimeMillis());
        //...這裡做一些其它任務
        System.out.println("資料:"+data.getResult());
        System.out.println("獲取完畢 "+System.currentTimeMillis());
    }
}

(2)Client的實現

client主要實現了獲取FutureData,開啟構造RealData的執行緒,並在接受請求後,很快的返回FutureData。

public class Client {
    public Data request(String queryStr){
        FutureData futureData = new FutureData();
        new Thread(new Runnable() {
            @Override
            public void run() {
                RealData realData =  new RealData(queryStr);
                futureData.setRealData(realData);
            }
        }).start();
        return futureData;
    }
}

(3)Data的實現

Data是一個介面,提供了getResult()方法。

public interface Data {
    String getResult();
}

(4)FutureData的實現

FutureData 實現了一個快速返回的RealData 包裝。它只是一個包裝,或者說是一個RealData 的虛擬實現 。因此,它可以很快被構造並返回。當使用FutureData的getResult()方法時,程式會阻塞,等待RealData()被注入到程式中,才使用RealData的getResult()方法返回。

public class FutureData implements Data {
    private  RealData realData = null;
    private  boolean isReady = false;

    synchronized public void setRealData(RealData realData){
        if (isReady){
            return;
        }
        this.realData = realData;
        isReady = true;
        notifyAll(); //通知所有等待的執行緒繼續執行
    }

    @Override
    synchronized public String getResult() {
        while (!isReady){
            try {
                System.out.print("...waiting...");
                wait(); //使當前執行緒在此處進行等待,直到被通知後繼續執行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.result;
    }
}

(5)RealData 的實現

RealData 是最終需要使用的資料模型,它的構造很慢。在這裡,使用sleep()函式模擬這個過程。

public class RealData implements Data {
    protected String result;

    public RealData(String para) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = "["+para+"]";
    }

    @Override
    public String getResult() {
        return result;
    }
}

執行結果:

請求完畢 1537520554813
...waiting...
資料:[name]
獲取完畢 1537520555890

程式執行的流程是Main執行緒去獲取資料,但是資料還在處理中,於是Main執行緒進入等待狀態,當資料處理完並通知等待所有等待的執行緒之後,Main執行緒得以繼續執行下去。

2.JDK的內建實現

Future模式如此常用,以至於在JDK的併發包中,就已經內建了一種Future模式的實現了。

示例程式:

public class RealData implements Callable<String> {
    private String para;

    public RealData(String para) {
        this.para = para;
    }

    @Override
    public String call() throws Exception {
        //這裡是真實的業務邏輯
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "["+para+"]";
    }
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //傳入RealData到FutureTask
        FutureTask<String> futureTask = new FutureTask<String>(new RealData("name"));
        //建立一個執行緒池
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //在這裡開啟執行緒執行RealData的call()方法
        executorService.submit(futureTask);
        System.out.println("請求完畢 "+System.currentTimeMillis());
        //...這裡進行一些其它操作
        System.out.println("資料:"+futureTask.get());
        System.out.println("獲取完畢 "+System.currentTimeMillis());
        //啟動一個有序的關閉,之前提交的任務將被執行,但是不會接受新的任務。
        executorService.shutdown();
    }
    
}

執行結果:

請求完畢 1537521833970
資料:[name]
獲取完畢 1537521834977

Callable介面是一個使用者自定義實現的介面。在應用程式中,通過實現Callable介面的call()方法,指定FutureTask的實際內容和返回物件。

Future介面提供的執行緒控制功能有:

//取消任務
boolean cancel(boolean mayInterruptIfRunning)
//是否已經取消
boolean isCancelled()
//是否已經完成
boolean isDone()
//取得返回物件
V get() throws InterruptedException, ExecutionException
//取得返回物件,可以設定超時時間
V get(long timeout, TimeUnit unit)

總結

Future模式的核心在於去除了主函式中的等待時間,並使得原來需要等待的時間段可以用於處理其他的業務邏輯,從而充分利用計算機資源。

作者:像風一樣

出處:https://www.cnblogs.com/yueshutong/p/9687662.html

鄭州男科醫院

鄭州男科哪家好

鄭州看男科哪家醫院好

鄭州看男科哪家醫院好

相關文章