Future模式

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Main {
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 Other Job Begin");

try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("data1 = " + data1.getContent());
System.out.println("data3 = " + data3.getContent());
System.out.println("data2 = " + data2.getContent());
System.out.println("Main End");
}
}

Host类

Host类首先会创建FutureData的实例。这并不会耗费很长时间。该实例会被作为返回值返回给调用者。

接着,它会启动一个新的线程并在新线程中创建RealData实例。虽然创建RealData的实例需要花费很长的时间,但这是在新线程中进行的,并不会影响Main类的线程的处理。

新线程会努力地创建RealData实例。当realData创建完成后,线程会调用setReadData方法将其设置到future字段中。由于创建realData会花费一些时间,所以设置future字段就是稍后的事情了。

接着调用了request方法的线程会在新线程启动后拿到返回值future并立即返回。

总结起来,执行request的线程会做以下三件事:

  1. 创建FutureData的实例
  2. 启动一个新线程,用于创建RealData
  3. 将FutureData的实例作为返回值返回给调用者。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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() {
    public void run() {
    RealData realData = new RealData(count, c);
    future.setRealData(realData);
    }
    }.start();
    System.out.println(" request(" + count + ", " + c + ") END");
    return future;
    }
    }

Data接口

1
2
3
4
public interface Data {
public abstract String getContent();
}

FutureData类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class FutureData implements Data {
private RealData realData = null;
private boolean ready = false;

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

this.realData = realData;
this.ready = true;
notifyAll();
}

public synchronized String getContent() {
while (!ready) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.getContent();
}
}

RealData类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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) {
e.printStackTrace();
}
}
System.out.println(" making RealData(" + count + ", " + c + ") END");
this.content = new String(buffer);
}

public String getContent() {
return content;
}
}
0%