14.Java中的Future模式
jdk1.7.0_79
本文实际上是对上文《13.ThreadPoolExecutor线程池之submit方法》的一个延续或者一个补充。在上文中提到的submit方法里出现了FutureTask,这不得不停止脚步将方向转向Java的Future模式。
Future是并发编程中的一种设计模式,对于多线程来说,线程A需要等待线程B的结果,它没必要一直等待B,可以先拿到一个未来的Future,等B有了结果后再取真实的结果。
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable); //主线程需要callable线程的结果,先拿到一个未来的Future
System.out.println(future.get()); //有了结果后再根据get方法取真实的结果,当然如果此时callable线程如果没有执行完get方法会阻塞执行完,如果执行完则直接返回结果或抛出异常
也就是说,Future它代表一个异步计算的结果。

上面就代表了Future模式的执行原理,根据网上的例子,我们可以来自己实现一个Future模式。
package com.future; /**
* 数据结果
* Created by yulinfeng on 6/18/17.
*/
public interface Data {
String getResult() throws InterruptedException;
}
package com.future; /**
* 结果的真实计算过程
* Created by yulinfeng on 6/18/17.
*/
public class RealData implements Data {
protected String data; public RealData(String data) {
try {
System.out.println("正在计算结果");
Thread.sleep(3000); //模拟计算
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data + “ world”;
} public String getResult() throws InterruptedException {
return data;
}
}
package com.future; /**
* 真实结果RealData的代理
* Created by yulinfeng on 6/18/17.
*/
public class FutureData implements Data {
RealData realData = null; //对RealData的封装,代理了RealData
boolean isReady = false; //真实结果是否已经准备好 public synchronized void setResultData(RealData realData) {
if (isReady) {
return;
}
this.realData = realData;
isReady = true;
notifyAll(); //realData已经被注入到了futureData中,通知getResult方法
} public synchronized String getResult() throws InterruptedException {
if (!isReady) {
wait(); //数据还未计算好,阻塞等待
}
return realData.getResult();
}
}
package com.future; /**
* Client主要完成的功能包括:1. 返回一个FutureData;2.开启一个线程用于构造RealData
* Created by yulinfeng on 6/18/17.
*/
public class Client { public Data request(final String string) {
final FutureData futureData = new FutureData(); /*计算过程比较慢,单独放到一个线程中去*/
new Thread(new Runnable() { public void run() {
RealData realData = new RealData(string);
futureData.setResultData(realData);
}
}).start(); return futureData; //先返回一个“假”的futureData
}
}
/**
* 负责调用Client发起请求,并使用返回的数据。
* Created by yulinfeng on 6/18/17.
*/
public class Main {
public static void main(String[] args) throws InterruptedException {
Client client = new Client();
System.out.println("准备计算结果");
Data data = client.request("hello"); //立即返回一个“假”的futureData,可以不用阻塞的等待数据返回,转而执行其它任务
System.out.println("执行其它任务");
Thread.sleep(3000); //模拟执行其它任务
System.out.println("数据的计算结果为:" + data.getResult());
}
}
仔细阅读以上程序对Future模式的实现不难发现,Future模式是异步请求和代理模式的结合。当然在JDK中已经为我们实现好了Future模式。
修改RealData类:
package com.future; import java.util.concurrent.Callable; /**
* 结果的真实计算过程
* Created by yulinfeng on 6/18/17.
*/
public class RealData2 implements Callable<String> {
protected String data; public RealData2(String data) {
this.data = data;
}
public String call() throws Exception {
try {
System.out.println("正在计算结果");
Thread.sleep(2000); //模拟计算结果
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data + " world";
return data;
}
}
修改Main测试类:
package com.future; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; /**
* 负责调用Executor的submit,并使用返回的数据。
* Created by yulinfeng on 6/18/17.
*/
public class Main2 { public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService client = Executors.newSingleThreadExecutor(); //类似Client
System.out.println("准备计算结果");
Future<String> data = client.submit(new RealData2("hello")); //类似Client.request
System.out.println("执行其它任务");
Thread.sleep(3000);
System.out.println("数据的计算结果为:" + data.get());
}
}
现在回到上文还未解决完的AbstractExecutorService#submit方法。
类比上面的Client#request方法,在Client#request中先创建一个FutureData实例,而在AbstractExecutorService#submit中则是创建一个FutureTask实例,接着Client#request新创建一个线程用于异步执行任务,并直接返回FutureData,而在AbstractExecutorService#submit中同样也将任务交给了execute方法,并直接返回FutureTask。当然JDK中Future模式的实现更为复杂。
在《12.ThreadPoolExecutor线程池原理及其execute方法》中我们讲解了execute方法,在ThreadPoolExecutor$Worker#runWorker方法第1145行中是对task任务的调用:
//ThreadPoolExecutor$Worker#runWorker
task.run();
submit调用execute以执行run方法,实际执行的是FutureTask中的run方法。在FutureTask#run中,可以看到对任务Callable类型的task异步的执行,以及结果的保存。
14.Java中的Future模式的更多相关文章
- Java中的Future模式原理自定义实现
摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...
- (转)轻松学,Java 中的代理模式及动态代理
背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...
- Java中的Future相关
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...
- java中 immutable,future,nio
什么是Future? 用过Java并发包的朋友或许对Future (interface) 已经比较熟悉了,其实Future 本身是一种被广泛运用的并发设计模式,可在很大程度上简化需要数据流同步的并发应 ...
- Java中的代理模式
代理模式在Java Web的框架中经常使用到.比如说在对数据库的访问中,核心功能是对数据库的增删改查,而连接数据库.处理事务等功能我们在开发中也要考虑到.所以我们将数据库的CRUD抽象到接口中,然后实 ...
- 说说Java中的代理模式
今天看到传智播客李勇老师的JDBC系列的第36节——通过代理模式来保持用户关闭连接的习惯.讲的我彻底蒙蔽了,由于第一次接触代理模式,感到理解很难,在博客园找到一篇文章,先记录如下: 引用自java设计 ...
- 谈谈Java中的代理模式
首先来看一下代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用, 其特征是代理类与 ...
- java中的dao模式
java中Dao模式 什么是DAO 1.Data Access Object(数据存取对象) 2.位于业务逻辑和持久化数据之间 3.实现对持久化数据的访问 DAO模式的作用 1隔离业务逻辑代码 ...
- Java中的单利模式
单利模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...
随机推荐
- Linux基础测试--11道题
000.创建一个目录/data mkdir /data 001.在/data 下面创建一个文件oldboy.txt touch /data/oldboy.txt 002.为oldboy.txt 增加内 ...
- 我的Python---1
在学习Python两周后的今天,第一次做下总结.在昨天,我发现了这个博客,并且风也似的注册.申请,然后成功了,感谢管理员. 实际上,现在回想起来我第一次接触编程时在高一的计算机课上.那时候只有语数外理 ...
- Linux环境下用户空间与内核空间数据的交换方式
在linux环境开发过程中,经常会需要在用户空间和内核空间之间进行数据交换. 介绍了 Linux 系统下用户空间与内核空间数据交换的几种方式 第一节:使用procfs实现内核交互简明教程(1) 第二节 ...
- mysql行列转换方法总结
这是一道行转列并且构造交叉表的问题: http://topic.csdn.net/u/20090530/23/0b782674-4b0b-4cf5-bc1a-e8914aaee5ab.html 数据样 ...
- Angular简易分页设计(一):基本功能实现
(首先声明本文来自博客园本人原创,转载请说明出处.欢迎关注:http://www.cnblogs.com/mazhaokeng/p/6752990.html) 之前网站的后台管理为了图快,把Jquer ...
- dva框架使用mock.js模拟数据 + fetch请求数据
what DVA? Dva是基于Redux做了一层封装,对于React的state管理,有很多方案,我选择了轻量.简单的Dva. dva 可以很方便就使用mock.js进行数据的模拟. 只需要三步,即 ...
- Qt:添加点击事件的Label并显示图片
1.给label添加点击事件 Qt中原本的label是没有点击事件的,如果想添加点击事件的话,可以继承QLabel类并重载鼠标事件(比如mousePressedEvent),然后在鼠标事件中发送一个信 ...
- SQLServer中使用扩展事件获取Session级别的等待信息以及SQLServer 2016中Session级别等待信息的增强
本文出处:http://www.cnblogs.com/wy123/p/6835939.html 什么是等待 简单说明一下什么是等待:当应用程序对SQL Server发起一个Session请求的时候, ...
- redis集群添加删除节点
Redis3.0集群添加节点 1:首先把需要添加的节点启动 cd /usr/local/cluster/ mkdir 7006 cp /usr/local/cluster/redis.conf /u ...
- 第三章 霍夫变换(Hough Transform)
主要内容: 霍夫变换的作用 霍夫变换检测直线的原理 霍夫变换检测圆的原理 OpenCV中的霍夫变换 1.霍夫变换检测直线原理 霍夫变换,英文名称Hough Transform,作用是用来检测图像中的直 ...