Java多线程之Future模式

1、什么是Future模式

当某一程序提交了一个请求,期望得到一个答复,但是这个请求需要处理的时间可能很长,传统模式下这个请求是同步的,客户端必须等待请求响应之后才能执行其他操作。而在Future模式下客户端立刻拿到一个伪造的数据(相当于商品的订单,而非商品本身),而客户端在此期间可以调用其他业务逻辑,充分的利用了等待时间,这就是Future模式的核心所在。这样在整个调用过程中,就不存在无谓的等待,充分的利用了所有的时间片,从而提高了整体的响应速度。

举个例子,在金融行业叫期权,市场上有看跌期权和看涨期权,你可以在现在(比如九月份)购买年底(十二月)的石油,假如你买的是看涨期权,那么如果石油真的涨了,你也可以在十二月份依照九月份商定的价格购买。扯远了,Future就是你可以拿到未来的结果。对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。

2、场景示例

场景一:

午饭时间到了,同学们要去吃饭了,小王下楼,走了20分钟,来到了肯德基,点餐,排队,吃饭一共花了20分钟,又花了20分钟走回公司继续工作,合计1小时。

场景二:

午饭时间到了,同学们要去吃饭了,小王点了个肯德基外卖,很快,他就拿到了一个订单(虽然订单不能当饭吃,但是有了订单,还怕吃不上饭嘛)。接着小王可以继续干活,30分钟后,外卖到了,接着小王花了10分钟吃饭,接着又可以继续工作了,成功地卷到了隔壁的小汪。

Java多线程之Future模式插图

在这两个场景中,小王的工作时间更加紧凑,特别是那些排队的时间都可以让外卖员去干,因此可以更加专注于自己的本职工作。场景1就是典型的函数同步调用,而场景2是典型的异步调用。

而场景2的异步调用,还有一个特点,就是它拥有一个返回值,这个返回值就是我们的订单。这个订单很重要,凭借着这个订单,我们才能够取得当前这个调用所对应的结果。

这里的订单就如同Future模式中的Future,这是一个合约,一份承诺。虽然订单不能吃,但是手握订单,不怕没吃的,虽然Future不是我们想要的结果,但是拿着Future就能在将来得到我们想要的结果。

因此,Future模式很好地解决了那些需要返回值的异步调用。

3、模式解析

  • Main:向Client发出请求
  • Host:返回Data数据,立即返回FutureData,去开启 ClientThread线程装配RealData
  • Data:返回数据接口
  • FutureData:Future数据构造很快,但是是一个虚拟的数据,需要装配RealData
  • RealData:真是数据

4、Future模式代码实现

public interface Data {

    public abstract String getContent() throws InterruptedException;
}
public class RealData implements Data {

    private final String content;

    public RealData(int count,char c) {
        System.out.println("开始初始化 RealData……");

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < count; i++) {
            sb.append(c);
        }

        System.out.println("RealData初始化完成……");
        this.content = sb.toString();
    }

    @Override
    public String getContent() {
        return this.content;
    }
}
public class FutureData implements Data {

    private RealData realData = null;
    private boolean flag = false;

    public synchronized void setRealData(RealData realData){
        if (flag){
            return;
        }

        // 当获取到数据后,
        this.realData = realData;
        this.flag = true;

        notifyAll();
    }

    @Override
    public String getContent()  {
        while (!flag){
            try {
                this.wait();  //
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return realData.getContent();
    }
}
public class Host {

    public Data request(final int count, final char c){
        System.out.println(" request(" + count + ", " + c  +" ) BEGIN");
        final FutureData future = new FutureData();
        new Thread(
                (() -> {
                    RealData realdata = new RealData(count, c);
                    future.setRealData(realdata);
                }))
        .start();

        System.out.println("   request(" + count + ", " + c + ") END");
        return future;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // write your code here
        System.out.println("main begin");
        Host  host = new Host();
        Data data1 = host.request(10, 'A');
        Data data2 = host.request(20, 'B');
        Data data3 = host.request(30, 'C');

        System.out.println("main otherJob BEGIN");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e){}
        System.out.println("main otherJob END");

        System.out.println("data1 = " + data1.getContent());
        System.out.println("data2 =" + data2.getContent());
        System.out.println("data3 =" + data3.getContent());
        System.out.println("main END");
    }
}

执行结果:

main begin
 request(10, A ) BEGIN
   request(10, A) END
 request(20, B ) BEGIN
   request(20, B) END
 request(30, C ) BEGIN
   request(30, C) END
main otherJob BEGIN
开始初始化 RealData……
开始初始化 RealData……
RealData初始化完成……
开始初始化 RealData……
RealData初始化完成……
RealData初始化完成……
main otherJob END
data1 = AAAAAAAAAA
data2 =BBBBBBBBBBBBBBBBBBBB
data3 =CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
main END

发表评论