1. 程式人生 > >JAVA多執行緒之Future模式

JAVA多執行緒之Future模式

Future模式有點類似於商品訂單。比如在網購時,當看中某一個商品時,就可以提交訂單,當訂單處理完成後,在家裡等待商品送貨上門即可。或者說更形象的我們傳送Ajax請求的時候,頁面是非同步的進行後臺處理,使用者無需一直等待請求的結果,可繼續瀏覽或操作其他內容。

下面看一個例子:

1.客戶端傳送請求

客戶端傳送請求,包裝類返回“假”的結果,同時建立一個執行緒去執行真實的操作。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FutureDemo {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
    //假設這裡在計算一個結果要花5秒鐘,我們就可以起一個執行緒讓他計算,在計算期間我們可以幹別的事情。
        Callable<Integer> call = new Callable<Integer>() {
            public Integer call() throws Exception {
                System.out.println("正在計算結果");
                Thread.sleep(5000);
                return 1;
            };
        };
        //把call交給FutureTask
        FutureTask<Integer> task = new FutureTask<>(call);
        //開啟執行緒去執行計算任務
        Thread t = new Thread(task);
        t.start();
        //在這期間,我們可以乾點別的
        Thread.sleep(10);
        System.out.println("乾點別的");
        //幹完之後,等計算完成,在愛拿到結果
        Integer result = task.get();
        System.out.println("拿到的結果為:"+result);
    }
}

下面,我們模擬一個場景,實現Future模式。 假設,現在你要去麵包店去買一塊蛋糕,但是,生產一塊蛋糕要花一段時間,你總不能一直等下去,這個時候,你可以先去上班,等下班回來之後,你再去取蛋糕。 我們就實現這麼一個場景:

public class FutureClient {

    public Data request(final String queryStr){
        //1 我想要一個代理物件(Data介面的實現類)先返回給傳送請求的客戶端,告訴他請求已經接收到,可以做其他的事情
        final FutureData futureData = new FutureData();
        //2 啟動一個新的執行緒,去載入真實的資料,傳遞給這個代理物件
        new Thread(new Runnable() {
            public void run() {
                //3 這個新的執行緒可以去慢慢的載入真實物件,然後傳遞給代理物件
                RealData realData = new RealData(queryStr);
                futureData.setRealData(realData);
            }
        }).start();

        return futureData;
    }
}

2.包裝類操作

package com.thread.mythread.conn015;

public interface Data {

    String getRequest();

}
public class FutureData implements Data{

    private RealData realData ;

    private boolean isReady = false;

    public synchronized void setRealData(RealData realData) {
        //如果已經裝載完畢了,就直接返回
        if(isReady){
            return;
        }
        //如果沒裝載,進行裝載真實物件
        this.realData = realData;
        isReady = true;
        //進行通知
        notify();
    }

    public synchronized String getRequest() {
        //如果沒裝載好 程式就一直處於阻塞狀態
        while(!isReady){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //裝載好直接獲取資料即可
        return this.realData.getRequest();
    }
}

3.真實結果

public class RealData implements Data{

    private String result ;

    public RealData (String queryStr){
        System.out.println("根據" + queryStr + "進行查詢,這是一個很耗時的操作..");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("操作完畢,獲取結果");
        result = "查詢結果";
    }

    public String getRequest() {
        return result;
    }
}

4、執行測試

package com.thread.mythread.conn015;

public class Main {

    public static void main(String[] args) throws InterruptedException {

        FutureClient fc = new FutureClient();
        Data data = fc.request("請求引數");
        System.out.println("請求傳送成功!");
        System.out.println("做其他的事情...");

        String result = data.getRequest();
        System.out.println(result);

    }
}

5、列印結果

請求傳送成功! 
做其他的事情… 
根據請求引數進行查詢,這是一個很耗時的操作.. 
操作完畢,獲取結果 
查詢結果