利用多线程实现Future模式
Posted 闲情偶寄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用多线程实现Future模式相关的知识,希望对你有一定的参考价值。
一、Futrue模式
客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订单,不是商品本身),用户也无需等待,先去执行其他的若干操作后,再去调用服务器已经完成组装的真实数据。
该模型充分利用了等待的时间片段。简单来说就是,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。
在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。
二、Future模式的代码实现
1、创建公共数据接口
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 /** 4 * Created by Root on 5/12/2017. 5 */ 6 public interface Data { 7 8 String getRequest(); 9 10 }
2、创建FutureData对象,当有程序想要获取RealData的时候,程序会被阻塞,等到RealData被注入才会使用getReal()方法
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 /** 4 * Created by Root on 5/12/2017. 5 */ 6 public class FutureData implements Data { 7 8 private RealData realData; 9 10 private boolean isReady = false; 11 12 public synchronized void setRealData(RealData realData) { 13 // 如果已经装载完毕了,就直接返回 14 if (isReady) { 15 return; 16 } 17 // 如果没装载,进行装载真实对象 18 this.realData = realData; 19 isReady = true; 20 // 进行通知 21 notify(); 22 } 23 24 @Override 25 public synchronized String getRequest() { 26 // 如果没装载好,程序就一直处于阻塞状态 27 while (!isReady) { 28 try { 29 wait(); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 } 34 // 装载好了直接获取数据即可 35 return this.realData.getRequest(); 36 } 37 }
3、真实数据RealData类
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 /** 4 * Created by Root on 5/12/2017. 5 */ 6 public class RealData implements Data { 7 8 private String result; 9 10 public RealData(String queryStr) { 11 System.out.println("根据" + queryStr + "进行查询,这是一个很耗时间的操作......"); 12 try { 13 Thread.sleep(5000); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 System.out.println("操作完毕,获取结果"); 18 result = "查询结果"; 19 } 20 21 @Override 22 public String getRequest() { 23 return result; 24 } 25 }
4、客户端代理类
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 /** 4 * Created by Root on 5/12/2017. 5 */ 6 public class FutureClient { 7 8 public Data request(final String queryStr) { 9 //1 我想要一个代理对象(Data接口的实现类)先返回给发送请求的客户端,告诉他请求已经接收到,可以做其他的事情 10 final FutureData futureData = new FutureData(); 11 //2 启动一个新的线程,去加载真实的数据,传递给这个代理对象 12 new Thread(new Runnable() { 13 @Override 14 public void run() { 15 //3 这个新的线程可以去慢慢的加载真实对象,然后传递给代理对象 16 RealData realData = new RealData(queryStr); 17 futureData.setRealData(realData); 18 } 19 }).start(); 20 21 return futureData; 22 } 23 24 }
5、测试调用
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 /** 4 * Created by Root on 5/12/2017. 5 */ 6 public class FutureTest { 7 8 public static void main(String[] args) { 9 FutureClient fc = new FutureClient(); 10 Data data = fc.request("请求参数"); 11 System.out.println("请求发送成功!"); 12 13 try { 14 //处理其他业务 15 //这个过程中,真实数据RealData组装完成,重复利用等待时间 16 System.out.println("做其它的事情......"); 17 Thread.sleep(2000); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 22 // 获取真实数据 23 String result = data.getRequest(); 24 System.out.println(result); 25 } 26 27 }
程序运行结果:
请求发送成功!
做其它的事情......
根据请求参数进行查询,这是一个很耗时间的操作......
操作完毕,获取结果
查询结果
第二种写法(没有实际运用过):
1 package com.ietree.basicskill.mutilthread.designpattern; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.Callable; 6 import java.util.concurrent.ExecutionException; 7 import java.util.concurrent.ExecutorService; 8 import java.util.concurrent.Executors; 9 import java.util.concurrent.Future; 10 11 /** 12 * Created by Root on 5/12/2017. 13 */ 14 public class FutureTest2 { 15 16 private static class Task implements Callable<String> { 17 @Override 18 public String call() throws Exception { 19 // 模拟真实事务的处理过程,这个过程是非常耗时的。 20 Thread.sleep(5000); 21 return "call return "; 22 } 23 } 24 25 public static void main(String[] args) throws InterruptedException, ExecutionException { 26 27 List<Future<String>> futures = new ArrayList<Future<String>>(); 28 ExecutorService executorService = Executors.newCachedThreadPool(); 29 30 System.out.println("已经提交资源申请"); 31 for (int i = 0; i < 10; i++) { 32 futures.add(executorService.submit(new Task())); 33 } 34 35 for (Future<String> future : futures) { 36 // 判断资源是不是已经准备完毕,准备完毕直接获取。 37 if (!future.isDone()) { 38 System.out.println("资源还没有准备好"); 39 } 40 System.out.println(future.get()); 41 } 42 executorService.shutdown(); 43 } 44 }
以上是关于利用多线程实现Future模式的主要内容,如果未能解决你的问题,请参考以下文章