Future模式的简单实现
From 《Java 高并发程序设计》
Future模式,核心思想是异步调用,就是当调用一个方法时,这个函数可能执行得很慢,就需要等待,但是有时候并不着急要这个结果,所以选择不去傻傻等待,而是做其他的事情。就好比”双十一”购物,你买到了想要的东西,那么你不可能等待它到货,然后才做另一件事情,你可能想继续购物其他的商品。而对于已经购买得商品,会生成一个订单,你只需要等待这个订单的快递通知(notify)就行了。
Future英文翻译为未来,可以认为无法立即给你想要的数据,但是给你一个标识,在未来你可以通过这个标识取获取想要的数据。这让我想到了Node.js的异步IO,事件驱动。
做一个简单的实现,类图是根据写的代码通过IDEA自动生成出来的,仅供参考。如下:定义一个接口Data,然后让FutureData和RealData实现它,并且,RealData是真正需要的数据,构建事件比较慢,而FutureData可以直接返回给调用者,Client执行方法,开启一个线程,去构建一个RealData,并返回一个FutureData,FutureData返回后,在RealData被构建完成后被填满,由于此时FutureData已经返回,程序可以继续执行向下耗时操作。
在Main方法中调用FutureData的getResult()方法,会发生wait()阻塞,直到FutureDat的setRealData()方法执行完毕,notifyAll所有的阻塞线程。注意wait和notify需要包含在synchronized语句中。
Data
package future;
/**
* 文件描述:
* 作者: bamboo
* 时间: 2016/11/28
*/
public interface Data {
String getResult();
}
RealData
构造很慢,使用sleep模拟操作。
package future;
/**
* 文件描述:
* 作者: bamboo
* 时间: 2016/11/28
*/
public class RealData implements Data {
protected final String result;
public RealData(String data) {
//设定构造函数构造得非常慢
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(data);
}
try {
System.out.println("构建需要10s,所以先做其他的事情");
Thread.sleep(10000);//10s 真的很慢了
} catch (InterruptedException e) {
e.printStackTrace();
}
this.result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
FutureData,是真实数据的代理。
让所有想要getResult的方法等待,并在构建数据完成的时候通知所有的线程,用到锁。
package future;
/**
* 文件描述:
* 作者: bamboo
* 时间: 2016/11/28
*/
public class FutureData implements Data {
protected RealData realData = null;
protected Boolean isReady = false;
public synchronized void setRealData(RealData realData) {
if (isReady) return;
this.realData = realData;
isReady = true;
notifyAll();
}
@Override
public synchronized String getResult() {
while (!isReady) {
try {
wait();
} catch (InterruptedException e) {
}
}
return realData.result;
}
}
Client
在请求数据的时候开启一个线程去获取数据,立即返回一个futureData,此时的futureData中并没有包含想要的RealData数据。
package future;
/**
* 文件描述:
* 作者: bamboo
* 时间: 2016/11/28
*/
public class Client {
public Data request(final String queryStr) {
final FutureData futureData = new FutureData();
new Thread() {
@Override
public void run() {
RealData realData = new RealData(queryStr);
futureData.setRealData(realData);
}
}.start();
return futureData;
}
}
Main
package future;
/**
* 文件描述:
* 作者: bamboo
* 时间: 2016/11/28
*/
public class Main {
public static void main(String[] args) {
Client client = new Client();
Data data = client.request("name");
System.out.println("请求完毕");
try {
//用数据处理代替一个很慢的过程
Thread.sleep(2000);
System.out.println("快速响应的数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据: " + data.getResult()); //在此处阻塞。
}
}
测试输出
future.Main
请求完毕
构建需要10s,所以先做其他的事情
快速响应的数据
数据: namenamenamenamenamenamenamenamenamename
Process finished with exit code 0