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)							//取得返回对象,可以设置超时时间
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章