1 Future的定义
future的原理是当你申请资源(计算资源或I/O资源)时,立即返回一个虚拟的资源,当真正使用的时候,再将虚拟的资源转化成真正的资源,相当于预获取。
Future,有点像期货市场的“期权”,是“对未来的一种凭证”,例如当我们买了某个房地产开发商的期房,交钱之后,开发商会给我们一个凭证(期权),这个凭证告诉我们等明年某个时候拿这个凭证就可以拿到我们所需要的房子,但是现在房子还没建好。我们目前手里有的只是一个虚拟的不能入住的房子(即期权),当我们要求要入住时,如果房子还没建好,那么就会阻塞,如果已经建好,那么就可以将期权换成了真正的房子,然后入住进去。
2 Future要解决的问题
Future设计模式是并发程序设计中的重要模式,主要是为了提高执行效率和资源利用率,避免在等待处理结果时空等。
下面两幅图展示了串行程序的程序执行过程和Future模式的程序执行流程:
(1) 串行程序:
(2) 并行程序:
3 Future涉及的角色
(1)Client:返回Data对象,立即返回FutureData,并开启新的线程去装配RealData。
(2)Data:返回数据的接口。
(3)FutureData:虚拟数据,构造很快,需要装配RealData。
(4)RealData:实际数据,构造很慢,需要开启一个线程去完成。
FutureData可以很快返回,但是当要请求实际数据时,如果数据还没准备好,那么将阻塞(wait),当数据准备好后,将会调用notify。
4 自己实现Future设计模式
(1)Client.java
public class Client {
public Data requestContent(final String name) {
final FutureData futureData=new FutureData();
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
/**
* RealData的构建很慢,在一个线程中去执行。
*/
RealData realData=new RealData(name);
futureData.setRealData(realData);
}
}.start();
//realData没有构建完成也可以返回这个对象
return futureData;
}
public static void main(String[] args)throws Exception {
Client client=new Client();
//发送一个请求
Data data=client.requestContent("hello");
/**
* 发送请求之后可以进行一些其他的操作
* 这里用sleep模拟,与此同时另一个线程在构建realData,然后赋值给futureData
*/
Thread.sleep(1000);
//获取content,如果还没有准备好,则会阻塞
System.out.println(data.getContent());
}
}
(2)Data接口:
public interface Data {
public String getContent();
}
(3)FutureData.java
public class FutureData implements Data{
private RealData realData;
private boolean isReady;
public synchronized void setRealData(RealData realData) {
if (isReady) {
return;
}
this.realData=realData;
isReady=true;
notifyAll();
}
@Override
public synchronized String getContent() {
// TODO Auto-generated method stub
while(!isReady){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return realData.getContent();
}
}
(4)RealData.java
public class RealData implements Data {
private List<String> list;
public RealData(String name) {
// TODO Auto-generated constructor stub
list=new ArrayList<String>();
for(int i=0;i<10000;i++){
list.add(name+i);
}
}
@Override
public String getContent() {
// TODO Auto-generated method stub
return list.get(1000);
}
}
5 JDK的内置实现
(1)RealContent.java
public class RealContent implements Callable<String> {
private List<String> list;
public RealContent(String name) {
// TODO Auto-generated constructor stub
list=new ArrayList<String>();
for(int i=0;i<10000;i++){
list.add(name+i);
}
}
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return list.get(1000);
}
}
(2)LearnFuture.java
public class LearnFuture {
public static void main(String[] args) throws Exception{
/**
* FutureTask implements RunnableFuture
*
* 而 RunnableFuture<V> extends Runnable, Future<V>
*
* 因此使用FutureTask既可以作为线程要执行的任务,又可以通过它来获取线程处理的结果
*/
FutureTask<String> task=new FutureTask<String>(new RealContent("hello"));
ExecutorService executorService=Executors.newFixedThreadPool(1);
//发送请求
executorService.submit(task);
//发送请求后,可以进行其他操作,这里用sleep模拟
Thread.sleep(1000);
//获取处理的结果,如果还没有处理完,则会阻塞
System.out.println(task.get());
}
}