文章内容
1、什么是Future模式
当某一程序提交了一个请求,期望得到一个答复,但是这个请求需要处理的时间可能很长,传统模式下这个请求是同步的,客户端必须等待请求响应之后才能执行其他操作。而在Future模式下客户端立刻拿到一个伪造的数据(相当于商品的订单,而非商品本身),而客户端在此期间可以调用其他业务逻辑,充分的利用了等待时间,这就是Future模式的核心所在。这样在整个调用过程中,就不存在无谓的等待,充分的利用了所有的时间片,从而提高了整体的响应速度。
举个例子,在金融行业叫期权,市场上有看跌期权和看涨期权,你可以在现在(比如九月份)购买年底(十二月)的石油,假如你买的是看涨期权,那么如果石油真的涨了,你也可以在十二月份依照九月份商定的价格购买。扯远了,Future就是你可以拿到未来的结果。对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。
2、场景示例
场景一:
午饭时间到了,同学们要去吃饭了,小王下楼,走了20分钟,来到了肯德基,点餐,排队,吃饭一共花了20分钟,又花了20分钟走回公司继续工作,合计1小时。
场景二:
午饭时间到了,同学们要去吃饭了,小王点了个肯德基外卖,很快,他就拿到了一个订单(虽然订单不能当饭吃,但是有了订单,还怕吃不上饭嘛)。接着小王可以继续干活,30分钟后,外卖到了,接着小王花了10分钟吃饭,接着又可以继续工作了,成功地卷到了隔壁的小汪。

在这两个场景中,小王的工作时间更加紧凑,特别是那些排队的时间都可以让外卖员去干,因此可以更加专注于自己的本职工作。场景1就是典型的函数同步调用,而场景2是典型的异步调用。
而场景2的异步调用,还有一个特点,就是它拥有一个返回值,这个返回值就是我们的订单。这个订单很重要,凭借着这个订单,我们才能够取得当前这个调用所对应的结果。
这里的订单就如同Future模式中的Future,这是一个合约,一份承诺。虽然订单不能吃,但是手握订单,不怕没吃的,虽然Future不是我们想要的结果,但是拿着Future就能在将来得到我们想要的结果。
因此,Future模式很好地解决了那些需要返回值的异步调用。
3、模式解析
- Main:向Client发出请求
- Host:返回Data数据,立即返回FutureData,去开启 ClientThread线程装配RealData
- Data:返回数据接口
- FutureData:Future数据构造很快,但是是一个虚拟的数据,需要装配RealData
- RealData:真是数据
4、Future模式代码实现
1 2 3 4 | public interface Data { public abstract String getContent() throws InterruptedException; } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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(); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | 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; } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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" ); } } |
执行结果:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | 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 |