当我们调用一个方法的时候,这个方法可能会执行的很慢,常规的做法是,等待这个很慢的函数执行完成之后,再进行下一步的操作;
Future所应对的场景:当执行较慢的函数返回的结果并不是实时调用,而是随后再使用时,我们可以先通过Future模式,让其执行,真正使用时才去获取结果值,或者阻塞;
其中涉及到几个概念:
Main 系统的调用者,当前执行的主函数
Client 返回FutureData对象,开起新线程执行
Data 对应的获取数据的接口
FutureData Future对象,很快的构造,能够通过该对象获取到真正的执行结果
RealData 真正的能够提供结果的对象,构造比较慢
简单实现:
public class Main {
public static void main(String[] args) {
Client client = new Client();
//立即返回的不是真正的data,而是futuredata对象
Data data = client.request();
System.out.println("请求完毕");
try {
//模拟其他业务逻辑,在其他逻辑执行的过程中,realdata已经创建完成
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("真实的结果为: " + data.getResult());
}
}
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 String getResult() {
while (!isReady){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.getResult();
}
}
public class RealData implements Data{
protected final String result;
public RealData(){
try {
//模拟创建时间很长的构造方法
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = "real data";
}
@Override
public String getResult() {
return "return result";
}
}
public interface Data {
String getResult();
}
public class Client {
public Data request(){
final FutureData future = new FutureData();
new Thread(() -> {
RealData realData = new RealData();
future.setRealData(realData);
}).start();
return future;
}
}
JDK中的实现方法:
public class Realdata implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "call result";
}
}
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new Realdata());
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(futureTask);
//模拟其他逻辑执行时间,在此期间,futuretask已经执行完成
Thread.sleep(2000);
System.out.println("result is " + futureTask.get());
}
}
jdk实现方便了我们的使用,只需要实现callable接口,并用futuretask提交到线程池执行即可;