参考文章:[高并发Java 七] 并发设计模式
核心思想是异步调用
非异步:
异步:
第一次的call_return由于任务还没完成,所以返回的是一个空的。
但是这个返回类似于购物中的订单,将来可以根据这个订单来得到一个结果。
所以Future模式意思就是,“未来”可以得到,就是指这个订单或者说是契约,“承诺”未来就会给结果。
调用者得到的是一个Data,一开始可能是一个FutureData,因为RealData构建很慢。在未来的某个时间,可以通过FutureData来得到RealData。代码实现:
public interface Data {
public String getResult ();
}
public class FutureData implements Data {
protected RealData realdata = null; //FutureData是RealData的包装
protected boolean isReady = false;
public synchronized void setRealData(RealData realdata) {
if (isReady) {
return;
}
this.realdata = realdata;
isReady = true;
notifyAll(); //RealData已经被注入,通知getResult()
}
public synchronized String getResult()//会等待RealData构造完成
{
while (!isReady) {
try {
wait(); //一直等待,知道RealData被注入
} catch (InterruptedException e) {
}
}
return realdata.result; //由RealData实现
}
}
public class RealData implements Data {
protected final String result;
public RealData(String para) {
// RealData的构造可能很慢,需要用户等待很久,这里使用sleep模拟
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
try {
// 这里使用sleep,代替一个很慢的操作过程
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
result = sb.toString();
}
public String getResult() {
return result;
}
}
public class Client {
public Data request(final String queryStr) {
final FutureData future = new FutureData();
new Thread() {
public void run()
{
// RealData的构建很慢,
//所以在单独的线程中进行
RealData realdata = new RealData(queryStr);
future.setRealData(realdata);
}
}.start();
return future; // FutureData会被立即返回
}
}
public static void main(String[] args) {
Client client = new Client();
// 这里会立即返回,因为得到的是FutureData而不是RealData
Data data = client.request("name");
System.out.println("请求完毕");
try {
// 这里可以用一个sleep代替了对其他业务逻辑的处理
// 在处理这些业务逻辑的过程中,RealData被创建,从而充分利用了等待时间
Thread.sleep(2000);
} catch (InterruptedException e) {
}
// 使用真实的数据
System.out.println("数据 = " + data.getResult());
}
接下来使用JDK提供的类和方法来实现刚刚的代码:
import java.util.concurrent.Callable;
public class RealData implements Callable {
private String para;
public RealData(String para) {
this.para = para;
}
@Override
public String call() throws Exception {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
return sb.toString();
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class FutureMain {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
// 构造FutureTask
FutureTask future = new FutureTask(new RealData("a"));
ExecutorService executor = Executors.newFixedThreadPool(1);
// 执行FutureTask,相当于上例中的 client.request("a") 发送请求
// 在这里开启线程进行RealData的call()执行
executor.submit(future);
System.out.println("请求完毕");
try {
// 这里依然可以做额外的数据操作,这里使用sleep代替其他业务逻辑的处理
Thread.sleep(2000);
} catch (InterruptedException e) {
}
// 相当于data.getResult (),取得call()方法的返回值
// 如果此时call()方法没有执行完成,则依然会等待
System.out.println("数据 = " + future.get());
}
}
这里要注意的是FutureTask是即具有 Future功能又具有Runnable功能的类。所以又可以运行,最后还能get。
当然如果在调用到future.get()时,真实数据还没准备好,仍然会产生阻塞状况,直到数据准备完成。
当然还有更加简便的方式:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureMain2 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(1);
// 执行FutureTask,相当于上例中的 client.request("a") 发送请求
// 在这里开启线程进行RealData的call()执行
Future future = executor.submit(new RealData("a"));
System.out.println("请求完毕");
try {
// 这里依然可以做额外的数据操作,这里使用sleep代替其他业务逻辑的处理
Thread.sleep(2000);
} catch (InterruptedException e) {
}
// 相当于data.getResult (),取得call()方法的返回值
// 如果此时call()方法没有执行完成,则依然会等待
System.out.println("数据 = " + future.get());
}
}
由于Callable是有返回值的,可以直接返回future对象。