Future模式
Future的意思就是未来、期货(经济学)用语。假设有一个方法需要花费很长时间才能获取运行结果。那么与其一直等待结果,不如先拿一张“提货单”。获取提货单并不耗费时间。这里的“提货单”就称之为Future角色。
获取Future劫色的线程会在稍后使用Future觉得来获取运行结果。这与凭着提货单去取蛋糕非常相似。如果运行结果已经出来了,那么直接领取即可;如果运行结果还没有出来,那么需要等待结果出来。
示例程序
在Future模式中,程序一旦发出请求,就会立即获取返回值。也就是说,会有下面这样的返回值。
1 | Data data = host.request(10, 'A'); |
但是,这里的返回值data并非请求的运行结果。为了获取请求的运行结果,我们刚刚启动了其他线程去计算。也就是说,这个返回值并不是蛋糕自身,而是蛋糕的提货单。
如下所示,过了一段时间之后,线程会先用data的getContent方法取获取运行结果。
这相当于使用提货单提取我们订购的蛋糕。如果其他线程处理完了请求,那么调用getContent的线程会立即从该方法返回;而如果其他线程还没有处理完请求,那么调用getContent的线程,则会继续等待运行结果。
类的一览表
名字 | 说明 |
---|---|
Main | 向Host发出请求并获取数据的类 |
Host | 向请求返回FutureData的实例的类 |
Data | 表示访问数据的方法的接口。由FutureData和RealData实现该接口。 |
FutureData | 表示RealData的“提货单”的类。其他线程会创建RealData的实例。 |
RealData | 表示实际数据的类。构造函数的处理会花费很长的时间。 |
Main类
Main类会调用request方法三次。接着它会接受三个Data(data1、data2、data3)作为返回值。这三个返回值实际上都是FutureData的实例,无需花费时间即可获取它们,类似蛋糕的提货单。因此,这相当于获取了三张提货单。
然后,为了表示Main类取执行了其他操作,我们让其sleep大约2秒。接下来,分别调用之前接收到的返回值data1、data2和data3的getContent方法来获取真正希望获取的结果。
1 | public class Main { |
Host类
Host类首先会创建FutureData的实例。这并不会耗费很长时间。该实例会被作为返回值返回给调用者。
接着,它会启动一个新的线程并在新线程中创建RealData实例。虽然创建RealData的实例需要花费很长的时间,但这是在新线程中进行的,并不会影响Main类的线程的处理。
新线程会努力地创建RealData实例。当realData创建完成后,线程会调用setReadData方法将其设置到future字段中。由于创建realData会花费一些时间,所以设置future字段就是稍后的事情了。
接着调用了request方法的线程会在新线程启动后拿到返回值future并立即返回。
总结起来,执行request的线程会做以下三件事:
- 创建FutureData的实例
- 启动一个新线程,用于创建RealData
- 将FutureData的实例作为返回值返回给调用者。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public 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() {
public void run() {
RealData realData = new RealData(count, c);
future.setRealData(realData);
}
}.start();
System.out.println(" request(" + count + ", " + c + ") END");
return future;
}
}
Data接口
1 | public interface Data { |
FutureData类
1 | public class FutureData implements Data { |
RealData类
1 | public class RealData implements Data { |