Future模式
Future模式是在多线程程序中设计中的一个非常常见的设计模式,它和Runnable非常类似,总整体而言,可以看作为有了返回值的Runnable。但是Future模式是继承Callable接口,重写call()方法的:
1 2 3 4 5 6 7 8
| import java.util.concurrent.Callable;
public class test implements Callable { @Override public Object call() throws Exception { return null; } }
|
Future模式的由来
Future模式的诞生也很贴近现实,我们的Runnable接口模式可以看做为很古老的 “一手交钱一手交货”,而Future模式则看作为,我们使用支票交易。这两者的区别在于哪里呢?Runnable要求你来交易的时候,必须去银行把钱全都取出来后,才可以交易,比如你运行的run方法,要工作完了,才可以交易,而Future模式则表示,我告诉你我能够给你钱,到时候你去银行取就可以了,我们先进行交易。这样的改进极大的提高了效率。
就如上图所示main代表主系统,client表示客户要处理的信息,data表示客户最终要获得的信息,realdata表示实际的数据,而使用future可以先返回一个futuredata,给data,futuredata是realdata包装,futuredata先返回结果值到data中,然后realdata再慢慢返回全部的数据。这种模式可以应用到大规模的抽奖当中,抽奖的时候可以先返回你是否抽到奖,之后再慢慢返回抽到的奖品的具体信息。
实现Future模式
我们可以试着手写出这样的模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| public interface Data { public String 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; System.out.println("真实数据到达,唤醒getResult"); notifyAll(); } @Override public synchronized String getResult() { while (!isReady){ try { System.out.println("等待真实数据处理完毕"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } return realData.result; } }
public class RealData implements Data { protected final String result;
public RealData(String result) { StringBuffer sb=new StringBuffer(); for (int i = 0; i <10 ; i++) { sb.append(result); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } }
this.result = sb.toString(); }
@Override public String getResult() { return null; } }
public class Client { public Data request (final String q){ final FutureData future=new FutureData(); new Thread(){ @Override public void run(){ System.out.println("开始对真实数据进行搭建"); RealData realData=new RealData(q); future.setRealData(realData); } }.start(); System.out.println("返回future"); return future; } }
public class test { public static void main(String[] args) { Client client=new Client(); Data data=client.request("qwe"); System.out.println("请求完毕"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("getResult:数据="+data.getResult()); }
}
返回future 请求完毕 开始对真实数据进行搭建 真实数据到达,唤醒getResult getResult:数据=qweqweqweqweqweqweqweqweqweqwe
|
可以看到,是先返回一个凭证,然后让程序接着运行下去,最后获得结果。
JDK内置的Future模式
这种Future模式在JDK当然内置也有,如图:
我们使用内置的Future模式来试试吧,它主要是继承一个Callable接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import java.util.concurrent.Callable;
public class RealData implements Callable { private String para;
public RealData(String para) { this.para = para; }
@Override public Object call() throws Exception { StringBuffer sb=new StringBuffer(); System.out.println("开始搭建真实数据"); for (int i = 0; i <10 ; i++) { sb.append(para); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("返回数据"); return sb.toString(); } }
|
然后再测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask;
public class test { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> f=new FutureTask<String>(new RealData("qwe")); ExecutorService es= Executors.newFixedThreadPool(1); es.submit(f); System.out.println("请求完毕"); try { System.out.println("做些其他的事情"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("数据="+f.get()); es.shutdown(); } }
请求完毕 做些其他的事情 开始搭建真实数据 返回数据 数据=qweqweqweqweqweqweqweqweqweqwe
|
注意:这里和run方法的区别是,如果你使用Runable接口去实现,那么在run方法执行完之后,数据就没了,或者直接输出,但是,这样是不会被自己给控制的。这里使用的future,想让它什么时候输出数据,就什么时候输出数据。