Future Pattern

什么是Future Pattern?

我现在去蛋糕店买蛋糕,下订单后,店员请我天黑之后再来取货,给我一张提货单。黄昏以后,我拿着提货单到蛋糕店取货,店员依据我的取货单,将蛋糕给了我。

假如现在需要一个执行起来需要一定时间的方法,我们就不需要执行结果出来了,而是直接获取一张“提货单”,因为获取“提货单”不需要花费时间,这时这个“提货单”就是Future参与者。

获取了Future参与者的线程,会在事后再去获取执行结果,就好像拿提货单去领取蛋糕一样。如果有了执行结果就马上取走蛋糕,否则等待到执行结果出现。

和往常一样,让我们还是先来看代码:

首先写一个Data接口,表达数据访问方式,让FutureData和RealData都实现这个接口:

package futurePattern;

public interface Data {
    public abstract String getContent();
}
然后写一个RealData类,用来表达实际数据:

package futurePattern;

public class RealData implements Data {
    private final String content;
    public RealData(int count, char c) {
        System.out.println("        making RealData(" + count + ", " + c + ") BEGIN");
        char[] buffer = new char[count];
        for (int i = 0; i < count; i++) {
            buffer[i] = c;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
        System.out.println("        making RealData(" + count + ", " + c + ") END");
        this.content = new String(buffer);
    }
    public String getContent() {
        return content;
    }
}
然后写一个FutureData类,作为Future(提货单):

package futurePattern;

public class FutureData implements Data {
    private RealData realdata = null;
    private boolean ready = false;
    public synchronized void setRealData(RealData realdata) {
        if (ready) {                        
            return;     // balk
        }
        this.realdata = realdata;
        this.ready = true;
        notifyAll();
    }
    public synchronized String getContent() {
        while (!ready) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        return realdata.getContent();
    }
}
接下来是对请求返回FutureData实例的类Host:
package futurePattern;

public class Host {
    public Data request(final int count, final char c) {
        System.out.println("    request(" + count + ", " + c + ") BEGIN");

        // (1) 建立FutureData的实体
        final FutureData future = new FutureData();

        // (2) 为了建立RealData的实体,启动新的线程
        new Thread() {                                      
            public void run() {                             
                RealData realdata = new RealData(count, c);
                future.setRealData(realdata);
            }                                               
        }.start();                                          

        System.out.println("    request(" + count + ", " + c + ") END");

        // (3) 取回FutureData实体,作为传回值
        return future;
    }
}
最后写一个测试类Test:

package futurePattern;

public class Test {
    public static void main(String[] args) {
        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");
    }
}
运行结果如下:

好,现在我们回头看看我们写了什么,程序的关键在哪。


在测试类Test中我们可以看到,程序执行了sleep,实际上是模拟在这个时间我们可以去做一些其他的事。

发出请求之后返回的data1,data2,data3是我们所说的future,这个东西的获取和我们真正想要的东西相比简直不花时间。

然后我们就可以通过future的getContent方法获取我们真正想要的。


在Host类中,他的request方法会建立一个FutureData实例,然后成为这个方法的返回值。

在这个类中会产生RealData的实例,不过是交给新的线程进行的。当RealData实例建立以后,就调用了setRealData方法,设置给future(相当于蛋糕做好了,准备让客人来取)。

总之调用request的线程(相当于买蛋糕的客人),做了以下操作:

1、建立FutureData的实例

2、为了建立RealData的实例,启动新的线程

3、取回FutureData,作为返回值

另外在这个类中,我们看到了一个request方法,这个方法不是synchronized的,但是实际上,这个方法也是线程安全的,因为request的参数和局部变量都是由单独的线程拥有的,而不是多个线程共享的。

而且request方法的参数和局部变量都被申明成了final,是为了在匿名内部类中使用。


在FutureData这个提货单类中,有一个ready字段,当蛋糕做好之后,可以把ready设置为true,然后调用notifyAll,唤醒所有在getContent方法里等待的线程。

另外setRealData中使用了Balking Pattern,防止setRealData被调用两次以上。

在getContent方法当中,由于必须等待setRealData方法设置realdata,因此这里用ready作为防卫条件,使用了Guarded Suspension Pattern,最后返回真实数据。当RealData实例被设置好之后,访问getContent方法而进入wait set的线程就会被notifyAll唤醒。


对于RealData类,作用只有返回真实数据,这个类没有用到synchronized,不处理等待到实例建立好为止的线程控制操作。不需要考虑多线程环境。


Future Pattern对这种需要很多时间的普通类加上提货单机制,使得多线程化后仍然可以提高执行性能。


Future Pattern的所有参与者

1、Client(委托人)参与者

Client参与者向Host参与者发出请求,Client参与者会马上得到VirtualData参与者,作为这个请求的返回值(实际上就是我们所说的future)。

2、Host参与者

Host参与者会建立出新的线程,开始建立RealData参与者。另一方面,对Client参与者(以VirtualData参与者的形式)返回VirtualData参与者。

3、VirtualData(虚拟的数据)参与者

VirtualData是用来统一代表Future参与者和RealData参与者的,相当于一个data接口。

4、Future(期货)参与者

Future是Host参与者传给Client参与者,被当作提货单的参与者。


Future Pattern 的优点

1、提升了throughput

我们使用这个模式使得Future Pattern不止可以达到如同Thread-Per-Message的响应度,还可以获取处理结果。

由于这个模式中在RealData参与者的生产过程中,CPU有一定的空闲时间,可以利用这个空闲时间处理其他操作,因此可以提高throughput

2、可以得到异步方法调用的“返回值”

Java提供的方法调用都是同步的,也就是说调用方法之后,只能一直前进到方法执行完。

在Thread-Per-Message Pattern中,通过在方法里启动新的线程来模仿出异步的操作(实际上方法调用本身仍然是同步的,所以称呼为模仿出)。只是用Thread-Per-Pattern不能得到处理结果,然而Future Pattern可以。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
3)A digital clock consists of a screen to display the time and a dial for setting in turn the year, month, day, hour and minute. Twisting the dial to the left reduces by one the value being changed but twisting it to the right increases it by one. Pushing the dial alters which value is being adjusted. At first, it is the year but after the dial is pushed once, it is the month, then after the dial is pushed again, it is the day and so on. Imagine the clock is represented by a class with attributes year, month, day etc. The following is what the code for a method rotateDialLeft() might look like. public void rotateDialLeft() { if (mode == YEAR_MODE) { year--; } else if (mode == MONTH_MODE) { month--; } else if (mode == DAY_MODE) { day--; } else if (mode == HOUR_MODE) { hour--; } else if (mode == MINUTE_MODE) { minute--; } } The code for rotateDialRight() is similar. Apply the Open-Closed Principle to explain why the above code is unsatisfactory from the design viewpoint, considering the possibility of future change to the code, giving an example of such a change. 5)Give the code required for the classes introduced in question 3), focusing on the code for a method selectState() which changes the value that is being adjusted from years to months. Make it clear in which classes the code is to be found. Assume the existence of other methods that are needed such as getMonthSetUpState(). 8)Suppose that in a multiplayer role-playing game, a class Client has a dependency to an interface Fighter with public methods attack(), defend() and escape(). The game designer now wishes for Client to use a class Wizard with three different but equivalent public methods castDestructionSpell(), shield() and portal(). Explain how it is possible to do this using an appropriate design pattern.
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值