一,Future模式
假设有一个方法需要花费很长的时间才能获取运行结果。那么,与其一直等待结果,不如先拿一张 提货单。获取提货单并不耗费时间。这里提货单就称为Future角色
获取Future角色的线程会在稍后使用Future角色来获取运行结果
在处理开始时先返回Future角色,等到其他线程出来终止后,在将结果设置到Future角色中。
二,示例程序
Data:访问数据的接口
RealData:实际处理数据的类
FutureData:表示RealData的提货单,
Host:先拿提货单future实例,开启新线程创建RealData实例
public interface Data { public abstract String getContent(); }
public class RealData implements Data { private final String content; public RealData(int count,char c){ System.out.println(" making RealData("+count+" , "+ c +") begin"); char[] buffer = new char[count]; for (int i = 0; i <count ; i++) { buffer[i] = c ; try { Thread.sleep(100); }catch (InterruptedException e){ } } System.out.println(" making RealData("+count+" , "+ c +") end"); this.content = new String(buffer); } @Override public String getContent() { return content; } @Override public String toString() { return "real.toString"; } }
public class FutureData implements Data { private RealData realData = null; private boolean ready = false; /** * 为Future类中的字段设置值 * @param realData */ public synchronized void setRealData(RealData realData) { if(ready){ return; } this.realData = realData; this.ready = true; notifyAll(); } /** * 还没有成功设置值之前 一直等待。设置成功后就返回值 * @return */ @Override public synchronized String getContent() { while (!ready){ try { wait(); }catch (InterruptedException e){ } } return realData.getContent(); } @Override public String toString() { return "feature.toString"; } }
public class Host { public Data request(final int count, final char c){ System.out.println(" request("+count+" , "+c+") begin"); //1,创建FutureData实例 final FutureData futureData = new FutureData(); //2,启动一个新线程去创建RealData实例,耗时操作 new Thread(){ @Override public void run() { RealData realData = new RealData(count,c); futureData.setRealData(realData); } }.start(); System.out.println(" request("+count+" , "+c+") end"); //3,将Future实例作为返回值返回给调用者 return futureData; } }
public class Test { public static void main(String[] args) { System.out.println(" main begin .........."); Host host = new Host(); Data data1 = host.request(10,'a'); System.out.println("虚拟数据:data1 = "+data1.toString()); Data data2 = host.request(20,'b'); System.out.println("虚拟数据:data2 = "+data2.toString()); Data data3 = host.request(30,'c'); System.out.println("虚拟数据:data3 = "+data3.toString()); System.out.println(" main OtherJobs begin"); try { //模拟主线程处理其他业务 Thread.sleep(2000); }catch (InterruptedException e){ } System.out.println(" main OtherJobs end"); System.out.println("真实数据:data1 = "+data1.getContent()); System.out.println("真实数据:data2 = "+data2.getContent()); System.out.println("真实数据:data3 = "+data3.getContent()); System.out.println(" main end .........."); } }
三,特点
1,提高吞吐量
首先这种模式可以提高程序响应性,但是耗时的操作花费的时间并没有减少啊,当程序在进行磁盘读写时,cpu处于等待状态,这时可以把cpu分配给其他的线程,就可以提高吞吐量了
四,Callable和Future
public class CallableAndFuture { public static void main(String[] args) { ExecutorService threadPool= Executors.newSingleThreadExecutor(); /* threadPool.submit() 返回有结果的 */ Future<String> future= //Future是用来接收submit的结果的。泛型和Callable的结果一样 threadPool.submit(new Callable<String>() {//这里泛型了, @Override public String call() throws Exception { Thread.sleep(1000); System.out.println("处理结果中。。。。"); Thread.sleep(1000); return "hello"; } }); System.out.println("等待结果"); try { System.out.println("拿到结果"+future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
/** * * CompletionService用于提交一组Callable任务,其task方法返回已完成的一个Callable任务对应的Future对象 */ public class CallableAndFuture2 { public static void main(String[] args) { ExecutorService threadPool2= Executors.newFixedThreadPool(10); CompletionService<Integer> completionService = new ExecutorCompletionService(threadPool2); for (int i = 0; i < 10; i++) { final int seq = i; completionService.submit(new Callable() { @Override public Integer call() throws Exception { Thread.sleep(new Random().nextInt(5000)); return seq; } }); } while (true){ try { System.out.println(completionService.take().get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } }