概述
假设有一个任务需要执行比较长的时间,通常需要等待任务执行结束或者出错才能返回结果,在此期间调用者只能陷入阻塞苦苦等待,对此Future设计模式提供了一种凭据式的解决方案。在我们日常生活中,关于凭据的使用非常多见,比如你去某西服工坊,西服的制作过程漫长,一般来说店家会给你开一个凭据,此凭据就是Future。
Future设计模式的核心:开辟新线程执行耗时的业务逻辑,去掉了主调用函数所在线程的等待时间,使得原本需要等待的时间去执行其他业务逻辑。
Future模式的主要角色
- Data:返回数据的接口
- FutureData:返回虚假数据,需要装载RealData
- RealData:真实数据
- FutureClient:返回Data对象,立即返回FutureData,并开启新线程去获取RealData
Data
public interface Data<T> {
T get() throws InterruptedException;
}
Data实现
public class DataFuture<T> implements Data<T> {
private volatile boolean done=false;
private T result;
//真实数据完成信号
public void done(T result) {
synchronized (this) {
this.result=result;
this.done=true;
this.notifyAll();
}
}
//返回数据
@Override
public T get() throws InterruptedException {
synchronized (this) {
//等待完成信号
while(!done) {
this.wait();
}
}
return result;
}
}
RealData
public interface RealData<T> {
//业务逻辑
T call();
}
FutureClient
public class FutureClient {
//FutureClient实现了业务逻辑和future的隔离
public <T> Data<T> submit(final RealData<T> task,Consumer<T> consumer){
//future
DataFuture<T> datafuture = new DataFuture<T>();
//开辟新线程执行业务逻辑,减少调用函数所在线程的等待时间
new Thread() {
@Override
public void run() {
//task.call()获取真实的数据
T result=task.call();
//通知凭据,数据已经采集完成
datafuture.done(result);
//回调
consumer.accept(result);
}
}.start();
//realdata还未执行完,先返回future(凭据)
return datafuture;
}
}
测试类
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InterruptedException {
FutureClient futureService = new FutureClient();
Data<String> future =futureService.submit(()->{
try {
//耗时的业务逻辑
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "FINISH";
},System.out::println);
System.out.println("==============");
System.out.println("==============");
System.out.println("==============");
}
打印结果
==============
==============
==============
FINISH
改进前的版本
虽然我们提交任务时不会进入任何阻塞,但是当调用者需要获取结果时,还是有可能陷入阻塞直到任务完成,因此前面我贴出的是带有回调接口的future实现。现在把没有实现回调函数的也贴出来,实际上就只有FutureClient有改变。
public class FutureClient {
public <T> Data<T> submit(final RealData<T> task){
DataFuture<T> synFutureImpl = new DataFuture<T>();
new Thread() {
@Override
public void run() {
T result=task.call();
synFutureImpl.done(result);
}
}.start();
return synFutureImpl;
}
}
测试类:
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InterruptedException {
FutureClient futureService = new FutureClient();
Data<String> future =futureService.submit(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "FINISH";
});
System.out.println("==============");
System.out.println("==============");
System.out.println("==============");
//如果数据还没好,就进行获取,可能也会陷入阻塞
System.out.println(future.get());
}