Future模式

1. Future模式简介

Future模式就是,当某一程序提交请求,期望得到一个答复。但是可能服务器程序对这个请求的处理比较慢,因此不可能马上收到答复。但是,在传统的单线程环境下,调用函数是同步的,它必须等到服务程序返回结果,才能继续进行其他处理。而Future模式下,调用方法是异步的,原本等待返回的时间段,在主调函数中,则可以处理其他的任务。传统的串行程序如下图所示:

https://images2015.cnblogs.com/blog/805129/201603/805129-20160317205509693-742725053.png

Future模式的处理流程:

https://images2015.cnblogs.com/blog/805129/201603/805129-20160317205558271-518468971.png

从图中可以看出,虽然call()本身是一个需要很长世间处理的程序。但是,服务程序不等数据处理完就立刻返回客户端一个伪数据,实现Future模式的客户端在拿到这个返回结果后,并不急于对它进行处理,而是去调用其它的业务逻辑,使call()方法有充分的时间去处理完成,这也是Future模式的精髓所在。 在处理完其他业务逻辑后,最后再使用处理比较费时的Future数据。这个在处理过程中,就不存在无谓的等待,充分利用了时间,从而提升了系统的响应和性能。

2. Future模式的核心结构

下面以一个经典的Future实现为例,简单介绍下Future的核心实现。代码中

  • Data接口:返回数据的接口;
  • FutureData类:实现Data接口,构造很快,返回一个虚拟的伪数据,需要装配RealData;
  • RealData类:实现Data接口,返回真实数据,构造比较慢;
  • Client:返回Data数据,立即返回FutureData数据,并开启线程装配RealData数据。
public interface Data {
    public String getResult();
}

public class FutureData implements Data {

    protected RealData realData = null;

    protected boolean isReady = false;
    //进行同步控制
    public synchronized void setResult(RealData realData){
        if(isReady){
            return;
        }
        System.out.println("FutureData.setResult()");
        this.realData=realData;
        isReady = true;
        notifyAll();

    }
    //实际调用返回RealDate的数据
    @Override
    public synchronized String getResult() {
        while(!isReady){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("FutureData.getResult()");
        return realData.result;
    }

public class RealData implements Data{

    protected final String result;

    public RealData(String s) {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < 10; i++) {
            sb.append(s);
            try {
                //模拟构造时间比较长
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }

        }

        System.out.println("RealData.RealData()");
        result = sb.toString();
    }

public class Client {
    public Data request(final String queryStr){
                //返回伪数据
        final FutureData futureData = new FutureData();
                //开启线程构造真实数据
        new Thread(){
            public void run(){
                RealData realData = new RealData(queryStr);
                futureData.setResult(realData);
            }
        }.start();
        //返回伪数据,等待真实数据加载
        return futureData;
    }
}

启动系统,调用Client发送请求:

public class TestMain {
    public static void main(String[] args) {
        Data data = new Client().request("123456");
        System.out.println(data);
        System.out.println(data.getResult());
    }
}

可以看出,FutureData是Future模式实现的关键,它实际是真实数据RealData的代理,封装了获取RealDate的等待过程.

3. JDK内置实现

在JDK的内置并发包中,就已经内置了一种Future的实现,提供了更加丰富的线程控制,其基本用意和核心理念与上面实现代码一致。

在JDK中的Future模式中,最重要的是FutureTask类,它实现了Runnable接口,可以作为单独的线程运行。在其run()方法中,通过Sync内部类,调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()时,将返回Callable接口的返回对象。FutureTask还可以对任务本身进行其他控制操作。

利用Callable接口实现上述例子相同的操作:

RealData类的实现:

public class Real1Data implements Callable<String>{

    private String reaString;

    public Real1Data(String reaString) {
        super();
        this.reaString = reaString;
    }

  
    @Override
    public String call() throws Exception {

        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < 10; i++) {
            sb.append(reaString);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO: handle exception
            }

        }

        return sb.toString();
    }

}

Client代码实现:

public class Test1Main {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> future =  new FutureTask<>(new Real1Data("1111"));

        ExecutorService exe = Executors.newFixedThreadPool(1);

        exe.submit(future);

        System.out.println("FutureTask");

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("FutureTask"+future.get());
    }
}

可以看出RealData的构造速度很快,其核心代码逻辑放在了call()中实现,不再需要Data和FutureData,直接通过RealData来构造FutureTask,将其作为单独的线程运行。在提交请求后,执行其他业务逻辑,做好通过FututeTask.get()方法,得到RealData的执行结果。

Future模式核心在于去除了主调用函数的等待时间,并使得原本需要等待的时间可以充分利用来处理其他业务逻辑,充分的利用了系统资源。

参考:
https://www.cnblogs.com/lcngu/p/5289605.html
https://www.jianshu.com/p/949d44f3d9e3

posted @ 2018-09-29 21:29  john8169  阅读(224)  评论(0编辑  收藏  举报