Future
Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用。当我们需要调用一个函数方法时,如果这个函数执行很慢,那么我们就要进行等待。但有时候,我们可能不急着要结果。因此,我们可以让被调者立即返回,让它在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获得需要的数据。
对于Future模式来说,虽然它无法立即给出你需要的数据。但是,它会返回给你一个契约,将来,你可以凭借这个契约去重新获取你需要的信息。
Future的简易实现
参与者 | 作用 |
---|---|
Main | 系统启动,调用Client发出请求 |
Client | 返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData |
Data | 返回数据的接口 |
FutureData | Future数据,构造很快,但是是一个虚拟的过程,需要装配RealData |
RealData | 真实数据,其构造是比较慢的 |
下面是data接口
public interface Data {
public String getResult();
}
FutureData:
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) {
e.printStackTrace();
}
}
return realData.result;
}
}
RealData
public class RealData implements Data{
protected final String result;
public RealData(String para){
//RealData的构造可能很慢,需要用户等待很久,这里用seelp模拟
StringBuffer sb = new StringBuffer();
for(int i = 0; i < 10; i++){
sb.append(para);
}
try{
//这里用sleep,代替一个很慢的操作过程
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
Client类:
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;
}
}
Main函数
public class Main {
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){
e.printStackTrace();
}
System.out.println("数据= " + data.getResult());
}
}
JDK中的Future模式
可以通过Future接口来得到真实的数据。RunnableFuture继承了Future和Ruuable接口,其中run()方法用于构造真实的数据。它有一个具体的实现FutureTask类。FutureTask有一个内部类Sync,一些实质性的工作,会委托Sync类实现。而Sync类最终会调用Callable接口,完成实际数据的组装工作。
具体使用
RealData
package JDKFuture;
import java.util.concurrent.Callable;
public class RealData implements Callable<String> {
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(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
return sb.toString();
}
}
FutureMain
package JDKFuture;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
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<String> future = new FutureTask<String>(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){
e.printStackTrace();
}
//相当于data.getResult(),取得call()方法的返回值
//如果此时call()方法没有执行完成,则依然会等待
System.out.println("数据 = " + future.get());
}
}
除了基本功能wait,JDK还为Future接口提供了一些简单的控制功能。
boolean cancel(boolean mayInterruptIfRunning); //取消任务
boolean isCancelled(); //是否已经取消
boolean isDone(); //是否已完成
V get() throws InterruptedException,ExecutionException; //取得返回对象
V get(long timeout,TimeUnit unit) //取得返回对象,可以设置超时时间