出自[Java多线程编程中Future模式的详解](http://blog.csdn.net/ghuil/article/details/41048017)
[TOC=1,2]
[Java](http://lib.csdn.net/base/javase "Java SE知识库")多线程编程中,常用的多线程设计模式包括:Future模式、Master-Worker模式、Guarded Suspeionsion模式、不变模式和生产者-消费者模式等。这篇文章主要讲述Future模式,关于其他多线程设计模式的地址如下:
关于其他多线程设计模式的地址如下:
关于Master-Worker模式的详解:[ Java多线程编程中Master-Worker模式的详解](http://blog.csdn.net/ghuil/article/details/41048005)
关于Guarded Suspeionsion模式的详解:[ Java多线程编程中Guarded Suspeionsion模式的详解](http://blog.csdn.net/ghuil/article/details/41047999)
关于不变模式的详解:[ Java多线程编程中不变模式的详解](http://blog.csdn.net/ghuil/article/details/41047979)
关于生产者-消费者模式的详解:[生产者-消费者模式Java详解](http://blog.csdn.net/ghuil/article/details/41044257)
# 1\. Future模式核心思想
Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑(根据《Java程序性能优化》)。
Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的时一直等待到这个答复收到时再去做别的事情,但如果利用Future设计模式就无需等待答复的到来,在等待答复的过程中可以干其他事情。
例如如下的请求调用过程时序图。当call请求发出时,需要很长的时间才能返回。左边的图需要一直等待,等返回数据后才能继续其他操作;而右边的Future模式的图中客户端则无需等到可以做其他的事情。服务器段接收到请求后立即返回结果给客户端,这个结果并不是真实的结果(是虚拟的结果),也就是先获得一个假数据,然后执行其他操作。
![](http://img.blog.csdn.net/20141112192253656)
# 2\. Future模式Java实现
**Client的实现**
Client主要完成的功能包括:1\. 返回一个FutureData;2.开启一个线程用于构造RealData。**
**
**[cpp]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. public class Client {
2. public Data request(final String string) {
3. final FutureData futureData = new FutureData();
4.
5. new Thread(new Runnable() {
6. @Override
7. public void run() {
8. //RealData的构建很慢,所以放在单独的线程中运行
9. RealData realData = new RealData(string);
10. futureData.setRealData(realData);
11. }
12. }).start();
13.
14. return futureData; //先直接返回FutureData
15. }
16. }
**Data的实现**
无论是FutureData还是RealData都实现该接口。**
**
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. public interface Data {
2. String getResult() throws InterruptedException;
3. }
**FutureData的实现**
FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程。
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. //FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程
2. public class FutureData implements Data {
3. RealData realData = null; //FutureData是RealData的封装
4. boolean isReady = false; //是否已经准备好
5.
6. public synchronized void setRealData(RealData realData) {
7. if(isReady)
8. return;
9. this.realData = realData;
10. isReady = true;
11. notifyAll(); //RealData已经被注入到FutureData中了,通知getResult()方法
12. }
13.
14. @Override
15. public synchronized String getResult() throws InterruptedException {
16. if(!isReady) {
17. wait(); //一直等到RealData注入到FutureData中
18. }
19. return realData.getResult();
20. }
21. }
**RealData的实现**
RealData是最终需要使用的数据,它的构造函数很慢。
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. public class RealData implements Data {
2. protected String data;
3.
4. public RealData(String data) {
5. //利用sleep方法来表示RealData构造过程是非常缓慢的
6. try {
7. Thread.sleep(1000);
8. } catch (InterruptedException e) {
9. e.printStackTrace();
10. }
11. this.data = data;
12. }
13.
14. @Override
15. public String getResult() {
16. return data;
17. }
18. }
**测试运行**
主函数主要负责调用Client发起请求,并使用返回的数据。
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. public class Application {
2. public static void main(String[] args) throws InterruptedException {
3. Client client = new Client();
4. //这里会立即返回,因为获取的是FutureData,而非RealData
5. Data data = client.request("name");
6. //这里可以用一个sleep代替对其他业务逻辑的处理
7. //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
8. Thread.sleep(2000);
9. //使用真实数据
10. System.out.println("数据="+data.getResult());
11. }
12. }
# 3\. Future模式的JDK内置实现
由于Future是非常常用的多线程设计模式,因此在JDK中内置了Future模式的实现。这些类在java.util.concurrent包里面。其中最为重要的是FutureTask类,它实现了Runnable接口,作为单独的线程运行。在其run()方法中,通过Sync内部类调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()方法时,将返回Callable接口的返回对象。同样,针对上述的实例,如果使用JDK自带的实现,则需要作如下调整。
首先,Data接口和FutureData就不需要了,JDK帮我们实现了。
其次,RealData改为这样:
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. import java.util.concurrent.Callable;
2.
3. public class RealData implements Callable {
4. protected String data;
5.
6. public RealData(String data) {
7. this.data = data;
8. }
9.
10. @Override
11. public String call() throws Exception {
12. //利用sleep方法来表示真是业务是非常缓慢的
13. try {
14. Thread.sleep(1000);
15. } catch (InterruptedException e) {
16. e.printStackTrace();
17. }
18. return data;
19. }
20. }
最后,在测试运行时,这样调用:
**[java]** [view plain](http://blog.csdn.net/ghuil/article/details/41048017# "view plain") [copy](http://blog.csdn.net/ghuil/article/details/41048017# "copy")
1. import java.util.concurrent.ExecutorService;
2. import java.util.concurrent.Executors;
3. import java.util.concurrent.FutureTask;
4.
5. public class Application {
6. public static void main(String[] args) throws Exception {
7. FutureTask futureTask =
8. new FutureTask(new RealData("name"));
9. ExecutorService executor =
10. Executors.newFixedThreadPool(1); //使用线程池
11. //执行FutureTask,相当于上例中的client.request("name")发送请求
12. executor.submit(futureTask);
13. //这里可以用一个sleep代替对其他业务逻辑的处理
14. //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
15. Thread.sleep(2000);
16. //使用真实数据
17. //如果call()没有执行完成依然会等待
18. System.out.println("数据=" + futureTask.get());
19. }
20. }
本文完。转载请注明出处。
参考文献
葛一鸣,Java程序性能优化.清华大学出版社.
- JVM
- 深入理解Java内存模型
- 深入理解Java内存模型(一)——基础
- 深入理解Java内存模型(二)——重排序
- 深入理解Java内存模型(三)——顺序一致性
- 深入理解Java内存模型(四)——volatile
- 深入理解Java内存模型(五)——锁
- 深入理解Java内存模型(六)——final
- 深入理解Java内存模型(七)——总结
- Java内存模型
- Java内存模型2
- 堆内内存还是堆外内存?
- JVM内存配置详解
- Java内存分配全面浅析
- 深入Java核心 Java内存分配原理精讲
- jvm常量池
- JVM调优总结
- JVM调优总结(一)-- 一些概念
- JVM调优总结(二)-一些概念
- VM调优总结(三)-基本垃圾回收算法
- JVM调优总结(四)-垃圾回收面临的问题
- JVM调优总结(五)-分代垃圾回收详述1
- JVM调优总结(六)-分代垃圾回收详述2
- JVM调优总结(七)-典型配置举例1
- JVM调优总结(八)-典型配置举例2
- JVM调优总结(九)-新一代的垃圾回收算法
- JVM调优总结(十)-调优方法
- 基础
- Java 征途:行者的地图
- Java程序员应该知道的10个面向对象理论
- Java泛型总结
- 序列化与反序列化
- 通过反编译深入理解Java String及intern
- android 加固防止反编译-重新打包
- volatile
- 正确使用 Volatile 变量
- 异常
- 深入理解java异常处理机制
- Java异常处理的10个最佳实践
- Java异常处理手册和最佳实践
- Java提高篇——对象克隆(复制)
- Java中如何克隆集合——ArrayList和HashSet深拷贝
- Java中hashCode的作用
- Java提高篇之hashCode
- 常见正则表达式
- 类
- 理解java类加载器以及ClassLoader类
- 深入探讨 Java 类加载器
- 类加载器的工作原理
- java反射
- 集合
- HashMap的工作原理
- ConcurrentHashMap之实现细节
- java.util.concurrent 之ConcurrentHashMap 源码分析
- HashMap的实现原理和底层数据结构
- 线程
- 关于Java并发编程的总结和思考
- 40个Java多线程问题总结
- Java中的多线程你只要看这一篇就够了
- Java多线程干货系列(1):Java多线程基础
- Java非阻塞算法简介
- Java并发的四种风味:Thread、Executor、ForkJoin和Actor
- Java中不同的并发实现的性能比较
- JAVA CAS原理深度分析
- 多个线程之间共享数据的方式
- Java并发编程
- Java并发编程(1):可重入内置锁
- Java并发编程(2):线程中断(含代码)
- Java并发编程(3):线程挂起、恢复与终止的正确方法(含代码)
- Java并发编程(4):守护线程与线程阻塞的四种情况
- Java并发编程(5):volatile变量修饰符—意料之外的问题(含代码)
- Java并发编程(6):Runnable和Thread实现多线程的区别(含代码)
- Java并发编程(7):使用synchronized获取互斥锁的几点说明
- Java并发编程(8):多线程环境中安全使用集合API(含代码)
- Java并发编程(9):死锁(含代码)
- Java并发编程(10):使用wait/notify/notifyAll实现线程间通信的几点重要说明
- java并发编程-II
- Java多线程基础:进程和线程之由来
- Java并发编程:如何创建线程?
- Java并发编程:Thread类的使用
- Java并发编程:synchronized
- Java并发编程:Lock
- Java并发编程:volatile关键字解析
- Java并发编程:深入剖析ThreadLocal
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
- Synchronized与Lock
- JVM底层又是如何实现synchronized的
- Java synchronized详解
- synchronized 与 Lock 的那点事
- 深入研究 Java Synchronize 和 Lock 的区别与用法
- JAVA编程中的锁机制详解
- Java中的锁
- TreadLocal
- 深入JDK源码之ThreadLocal类
- 聊一聊ThreadLocal
- ThreadLocal
- ThreadLocal的内存泄露
- 多线程设计模式
- Java多线程编程中Future模式的详解
- 原子操作(CAS)
- [译]Java中Wait、Sleep和Yield方法的区别
- 线程池
- 如何合理地估算线程池大小?
- JAVA线程池中队列与池大小的关系
- Java四种线程池的使用
- 深入理解Java之线程池
- java并发编程III
- Java 8并发工具包漫游指南
- 聊聊并发
- 聊聊并发(一)——深入分析Volatile的实现原理
- 聊聊并发(二)——Java SE1.6中的Synchronized
- 文件
- 网络
- index
- 内存文章索引
- 基础文章索引
- 线程文章索引
- 网络文章索引
- IOC
- 设计模式文章索引
- 面试
- Java常量池详解之一道比较蛋疼的面试题
- 近5年133个Java面试问题列表
- Java工程师成神之路
- Java字符串问题Top10
- 设计模式
- Java:单例模式的七种写法
- Java 利用枚举实现单例模式
- 常用jar
- HttpClient和HtmlUnit的比较总结
- IO
- NIO
- NIO入门
- 注解
- Java Annotation认知(包括框架图、详细介绍、示例说明)