并发模式(一)Future模式
2017-06-15 00:00
796 查看
并行设计模式是对一些常用的多线程结构的总结和抽象,与串行程序设计相比,并行程序更复杂。
接下来会记录这些模式的学习过程,一一成文,以便以后查阅和复习。
主要使用场景:
当对象创建后,其内部状态和数据不再发生任何变化;
对象需要被共享、被多线程频繁访问。
代码实现:
final修饰类,确保不能被继承,没有子类;
所有属性私有化,并用final标记,确保不会被修改;
移除setter方法和其他所有修改自身属性的方法;
构造函数的参数包括所有的属性,提供赋值的窗口。
在JDK中,所有基本类型的包装类、String都是使用不变模式实现的。
Client:返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData。
Data:返回数据的接口。
FutureData:Future数据,构造很快,但是是一个虚拟的数据,需要装配RealData。
RealData:真实数据,其构造过程是比较慢的。
FutureData其实是RealData的一个代理,实现RealData的延迟效果。
在Main方法中,直接通过
Future模式的核心在于除了主函数中的等待时间,并使得原本需要等待的时间可以用于其他业务逻辑的处理,充分利用了计算机资源,提高系统性能。
前言
常用的并发设计模式有Future模式、Master-Worker模式、Guarded Suspension模式、不变模式、生产者-消费者模式,在多线程环境中,合理使用模式,可以提高程序性能,优化程序设计。接下来会记录这些模式的学习过程,一一成文,以便以后查阅和复习。
不变模式
不变模式的实现很简单,这里说明一下。不变模式天生就是多线程友好的。一个对象一旦被创建,则它的内部状态将永远不会发生改变,没有一个线程可以修改其内部状态和数据,同时内部状态也不会自行发生改变。基于这些特性,不变模式的对象,在多线程环境中不需要同步控制。主要使用场景:
当对象创建后,其内部状态和数据不再发生任何变化;
对象需要被共享、被多线程频繁访问。
代码实现:
final修饰类,确保不能被继承,没有子类;
所有属性私有化,并用final标记,确保不会被修改;
移除setter方法和其他所有修改自身属性的方法;
构造函数的参数包括所有的属性,提供赋值的窗口。
在JDK中,所有基本类型的包装类、String都是使用不变模式实现的。
Future模式
概念
Future模式是多线程设计常用的一种设计模式,类似商品订单。商品下单后,会立即得到下单成功的通知,客户不用等待后续商家的操作,只等配送到家即可,下单后到收到商品这段时间,客户可以做其他事情,不用在家等着商品。Future模式也类似Ajax的异步请求,不用等待处理结果。处理流程
传统处理流程
客户端发出call请求,这个请求需要很长一段时间才能返回。客户端一直等待着,直到数据返回,随后进行其他业务处理。Future模式流程
服务程序不需要等待数据处理完成便立即返回客户端伪造的数据(相当于商品的订单,而不是实际商品),客户端拿到这个返回结果后,并不急于对其处理,而是利用等待的时间,调用其他业务逻辑。这就是Future模式的核心所在。主要参与者
Main:系统启动,调用client发出请求。Client:返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData。
Data:返回数据的接口。
FutureData:Future数据,构造很快,但是是一个虚拟的数据,需要装配RealData。
RealData:真实数据,其构造过程是比较慢的。
代码实现
Future模式结构图Main
//Future的简单实现。 // 系统启动,调用client发出请求 public class Main { public static void main(String[] args) { Client client = new Client(); //这里会立即返回,因为得到的是FutureData,而不是RealData Data data = client.request("name"); System.out.println("发送请求完毕。。。"); try { //模拟其他业务逻辑处理 //处理过程中,RealData被创建,充分利用了等待的时间。 System.out.println("Main 正在调用其他业务逻辑。。。"); Thread.sleep(1000); System.out.println("Main 其他业务处理完成。。。"); } catch (InterruptedException e) { e.printStackTrace(); } //使用真实的数据 System.out.println("数据= " + data.getResult()); } }
Client
//返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData public class Client { public Data request(final String requestStr){ final FutureData future=new FutureData(); //RealData构建过程很慢,所以在单独的线程中进行 new Thread(){ @Override public void run() { RealData realData=new RealData(requestStr); future.setRealData(realData); } }.start(); return future;//future会被立即返回 } }
Data
//返回数据的接口 public interface Data { public String getResult(); }
FutureData
//Future数据,构造很快,但是是一个虚拟的数据,需要装配RealData //FutureData是Future模式的核心,是RealData的真实代理,封装了等待RealData的过程。 public class FutureData implements Data { protected RealData realData=null;//FutureData是RealData的包装 protected boolean isReady=false; public synchronized void setRealData(RealData realData){ if (isReady){ return; } this.realData=realData; isReady=true; notifyAll();//RealData已被注入,通知getResult() } @Override public synchronized String getResult() { //等待RealData构造完成 while (!isReady){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } return realData.result;//由RealData实现 } }
RealData
//真是数据,其构造过程是比较慢的 public class RealData implements Data { protected final String result; public RealData(String para){ StringBuffer buffer=new StringBuffer(); System.out.println("RealData 正在构造真实数据。。。"); for (int i=0;i<10;i++){ buffer.append(para); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("RealData 真实数据构造完成。。。"); result=buffer.toString(); } @Override public String getResult() { return result; } }
FutureData其实是RealData的一个代理,实现RealData的延迟效果。
JDK的内置实现
JDK内置的Future模式
代码优化
使用JDK内置的Future模式优化代码,首先要实现Callable这个接口,Data、
FutureData、
Client对象就不需要了。
RealData
public class RealData implements Callable<String> { private String para; public RealData(String para) { this.para = para; } //call中写具体的业务逻辑 @Override public String call() throws Exception { //模拟真实业务逻辑,执行很慢 StringBuffer buffer=new StringBuffer(); System.out.println("RealData 正在构造真实数据。。。"); for (int i=0;i<10;i++){ buffer.append(para); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("RealData 真实数据构造完成。。。"); return buffer.toString(); } }
Main
在Main方法中,直接通过
RealData构造
FutureTask,作为单独的线程运行。
public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { //构造FutureTask FutureTask<String> future=new FutureTask<String>(new RealData("name")); ExecutorService executor= Executors.newFixedThreadPool(1); //执行FutureTask,相当于client.request()发送请求 //开启线程进行RealData的call()执行 executor.submit(future); System.out.println("发送请求完毕"); try { System.out.println("Main 正在调用其他业务逻辑。。。"); Thread.sleep(2000); System.out.println("Main 其他业务处理完成。。。"); } catch (InterruptedException e) { e.printStackTrace(); } //使用真实的数据 //相当于data.getResult(),取得call()方法的返回值 //如果call()方法没有执行完成,则依然会等待 System.out.println("数据= " + future.get()); } }
Future模式的核心在于除了主函数中的等待时间,并使得原本需要等待的时间可以用于其他业务逻辑的处理,充分利用了计算机资源,提高系统性能。
参考资料
葛一鸣:Java程序性能优化-让你的Java程序更快、更稳定相关文章推荐
- Future 模式详解(并发使用)
- 并发模型(一)——Future模式
- Java并发程序设计(十)设计模式与并发之Future模式
- 【Java高并发学习】Future模式
- 并发编程之Future模式的模拟实现
- AKKA的Future支持并发模式
- Future模式-并发编程
- 并发模型之Future设计模式
- Java高并发程序-Chapter4 并行模式与算法(第二十六讲)Future 模式
- 并发模式Future ,JAVA内置模块Callable接口实现 实例
- 并发编程-Future模式
- 并发程序设计之Future模式
- java并发包学习系列:future模式
- Future 模式详解(并发使用)
- future相比于其他并发设计模式的优势(“回调驱动(多线程环境下)”、“消息/事件驱动(Actor模型中))
- JAVA并发处理经验(四)并行模式与算法2:Future模式
- 并发模型(一)——Future模式
- 并发模型(一)——Future模式
- 【并发编程】Future模式及JDK中的实现
- Java高并发程序设计笔记(八)之Future设计模式