Java併發模式—Future模式

Future

Future模式是多線程開發中非常常見的一種設計模式,它的核心思想是異步調用。當我們需要調用一個函數方法時,如果這個函數執行很慢,那麼我們就要進行等待。但有時候,我們可能不急着要結果。因此,我們可以讓被調者立即返回,讓它在後臺慢慢處理這個請求。對於調用者來說,則可以先處理一些其他任務,在真正需要數據的場合再去嘗試獲得需要的數據。

對於Future模式來說,雖然它無法立即給出你需要的數據。但是,它會返回給你一個契約,將來,你可以憑藉這個契約去重新獲取你需要的信息。

Future的簡易實現

參與者 作用
Main 系統啓動,調用Client發出請求
Client 返回Data對象,立即返回FutureData,並開啓ClientThread線程裝配RealData
Data 返回數據的接口
FutureData Future數據,構造很快,但是是一個虛擬的過程,需要裝配RealData
RealData 真實數據,其構造是比較慢的

下面是data接口

public interface Data {
    public String getResult();
}

FutureData:

public class FutureData implements Data{
    protected RealData realData = null;
    protected boolean isReady = false;
    public synchronized void setRealData(RealData realData){
        if(isReady){
            return;
        }
        this.realData = realData;
        isReady = true;
        notifyAll();
    }
    @Override
    public synchronized String getResult() {
        while (!isReady){
            try{
                wait();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.result;
    }
}

RealData

public class RealData implements Data{
    protected final String result;
    public RealData(String para){
        //RealData的構造可能很慢,需要用戶等待很久,這裏用seelp模擬
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < 10; i++){
            sb.append(para);
        }
        try{
            //這裏用sleep,代替一個很慢的操作過程
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        result = sb.toString();
    }

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

Client類:

public class Client {
    public Data request(final String queryStr){
        final FutureData future = new FutureData();
        new Thread(){
            public void run(){                    //RealData的構建很慢,所以在單獨線程中進行
                RealData realData = new RealData(queryStr);
                future.setRealData(realData);
            }
        }.start();
        return future;
    }
}

Main函數

public class Main {
    public static void main(String[] args){
        Client client = new Client();
        //這裏會立即返回,因爲得到的是FutureData而不是RealData
        Data data= client.request("name");
        System.out.println("請求完畢");
        try{
            //這裏可以用一個sleep代替了對其他業務邏輯的處理
            //在處理這些業務邏輯的過程中,RealData被創建,從而充分利用了等待時間
            Thread.sleep(2000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("數據= " + data.getResult());
    }

}

JDK中的Future模式

p1

可以通過Future接口來得到真實的數據。RunnableFuture繼承了Future和Ruuable接口,其中run()方法用於構造真實的數據。它有一個具體的實現FutureTask類。FutureTask有一個內部類Sync,一些實質性的工作,會委託Sync類實現。而Sync類最終會調用Callable接口,完成實際數據的組裝工作。

具體使用

RealData

package JDKFuture;

import java.util.concurrent.Callable;

public class RealData implements Callable<String> {
    private String para;
    public RealData(String para){
        this.para = para;
    }
    @Override
    public String call() throws Exception{
        StringBuffer sb = new StringBuffer();
        for(int i = 0 ; i < 10; i++){
            sb.append(para);
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

FutureMain

package JDKFuture;

import org.omg.Messaging.SYNC_WITH_TRANSPORT;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class FutureMain {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
       //構造FutureTask
        FutureTask<String> future = new FutureTask<String>(new RealData("a"));
        ExecutorService executor = Executors.newFixedThreadPool(1);
        //執行FutureTask,相當與上例中的client.request("a")發送請求
        //在這裏開啓線程進行RealData的call()執行
        executor.submit(future);

        System.out.println("請求完畢");
        try{
            //這裏依然可以做額外操作,這裏使用sleep代替其他業務邏輯的處理
            Thread.sleep(2000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        //相當於data.getResult(),取得call()方法的返回值
        //如果此時call()方法沒有執行完成,則依然會等待
        System.out.println("數據 = " + future.get());
    }
}

除了基本功能wait,JDK還爲Future接口提供了一些簡單的控制功能。

boolean cancel(boolean mayInterruptIfRunning);				//取消任務
boolean isCancelled();										//是否已經取消
boolean isDone();											//是否已完成
V get() throws InterruptedException,ExecutionException; 	//取得返回對象
V get(long timeout,TimeUnit unit)							//取得返回對象,可以設置超時時間
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章