我理解的Future模式
学而时习之,不亦说乎!
--《论语》
什么是Future?
考虑一个场景,为了完成某个业务,我需要同时查询三张表的三条独立数据。但是呢,这三张表数据量很大,三条数据分别需要消耗4s,6s,8s才能查询出来。在不考虑其他耗时的情况下,按顺序查出这三条数据,需要消耗18s时间。因为这三条数据其实是无上下文关系的,我们可以想到,如果我使用三个线程同时进行查询,那么会消耗多少时间呢?应该是耗时最长的那条数据所需的时间8s。那么,这儿分别实现这两种方式的查询。
项目整体结构如下:

entity包是通用实体类,normal包下是普通方式的查询代码,future包下是使用future模式查询代码。
1.创建一个普通的java项目。
2.创建一个通用实体类User:
package com.zby.entity;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
3.使用普通方式按顺序查询的代码:
创建一个UserDao接口:
package com.zby.normal.dao;
import com.zby.entity.User;
public interface UserDao {
User queryUserByUsername(String username);
}
创建UserDao的实现类UserDaoImpl:
package com.zby.normal.dao.impl; import com.zby.entity.User;
import com.zby.normal.dao.UserDao; public class UserDaoImpl implements UserDao {
@Override
public User queryUserByUsername(String username) {
try {
System.out.println("开始对参数【" + username + "】进行数据库查询.....");
// 模拟数据库操作耗时
int sleepTime = username.length() * ;
Thread.sleep(sleepTime);
// 模拟数据库返回数据
User user = new User();
user.setUsername(username);
user.setPassword("");
System.out.println("完成对参数【" + username + "】进行数据库查询.....耗时" + sleepTime + "毫秒");
return user;
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
} }
测试类:
package com.zby.normal; import com.zby.entity.User;
import com.zby.normal.dao.UserDao;
import com.zby.normal.dao.impl.UserDaoImpl; public class GeneralApplication { public static void main(String[] args) {
long startTime = System.currentTimeMillis();
UserDao queryDao = new UserDaoImpl();
User lisi = queryDao.queryUserByUsername("lisi");
User wangwu = queryDao.queryUserByUsername("wangwu");
User zhangsan = queryDao.queryUserByUsername("zhangsan");
System.out.println("lisi:" + lisi);
System.out.println("wangwu:" + wangwu);
System.out.println("zhangsan:" + zhangsan);
System.out.println("操作总耗时" + (System.currentTimeMillis() - startTime) + "毫秒");
} }
控制台输出:
开始对参数【lisi】进行数据库查询.....
完成对参数【lisi】进行数据库查询.....耗时4000毫秒
开始对参数【wangwu】进行数据库查询.....
完成对参数【wangwu】进行数据库查询.....耗时6000毫秒
开始对参数【zhangsan】进行数据库查询.....
完成对参数【zhangsan】进行数据库查询.....耗时8000毫秒
lisi:User [username=lisi, password=]
wangwu:User [username=wangwu, password=]
zhangsan:User [username=zhangsan, password=]
操作总耗时18001毫秒
这个就很简单了,就是一般的数据库操作。要使用并发查询,需要考虑什么呢?
首先,dao是要改的,我们不能在查询时直接返回实体类对象,因为我们的查询不是实时的,没法直接获取到结果。那我们这儿就考虑使用一个类,封装返回的数据,提供一个get方法,在需要的时候才获取需要的结果数据;提供一个set方法,使用另外的线程去查询结果,查询完毕后使用set到里面去,这样get的时候就有数据了。但是,如果我在使用get的时候数据还没有获取完成,这时怎么办?这儿就需要使用线程的阻塞唤醒机制:当结果还在获取中调用了get方法,会阻塞当前线程,等待获取完成后唤醒get。
4.使用Future模式的查询代码:
封装数据的FutureData类:
package com.zby.future.data;
public class FutureData<T> {
private T data;
public synchronized void setData(T data) {
this.data = data;
notify();
}
public synchronized T getData() {
while (null == data) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return this.data;
}
}
改造后的UserDao接口:
package com.zby.future.dao; import com.zby.entity.User;
import com.zby.future.data.FutureData; public interface UserDao {
FutureData<User> queryUserByUsername(String username);
}
改造后的UserDao接口实现类UserDaoImpl:
package com.zby.future.dao.impl; import com.zby.entity.User;
import com.zby.future.dao.UserDao;
import com.zby.future.data.FutureData; /**
*
* @描述:
* @作者: zby
* @创建时间: 2017年9月13日
*/
public class QueryDaoImpl implements UserDao { @Override
public FutureData<User> queryUserByUsername(final String username) {
final FutureData<User> data = new FutureData<User>();
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始对参数【" + username + "】进行数据库查询.....");
// 模拟数据库操作耗时
int sleepTime = username.length() * ;
Thread.sleep(sleepTime);
// 模拟数据库返回数据
User user = new User();
user.setUsername(username);
user.setPassword("");
System.out.println("完成对参数【" + username + "】进行数据库查询.....耗时" + sleepTime + "毫秒");
data.setData(user);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
return data;
}
}
测试类:
package com.zby.future; import com.zby.entity.User;
import com.zby.future.dao.UserDao;
import com.zby.future.dao.impl.QueryDaoImpl;
import com.zby.future.data.FutureData; public class FutureApplication { public static void main(String[] args) {
long startTime = System.currentTimeMillis();
UserDao queryDao = new QueryDaoImpl();
FutureData<User> lisi = queryDao.queryUserByUsername("lisi");
FutureData<User> wangwu = queryDao.queryUserByUsername("wangwu");
FutureData<User> zhangsan = queryDao.queryUserByUsername("zhangsan");
System.out.println("lisi:" + lisi.getData());
System.out.println("wangwu:" + wangwu.getData());
System.out.println("zhangsan:" + zhangsan.getData());
System.out.println("耗时" + (System.currentTimeMillis() - startTime));
} }
控制台输出:
开始对参数【lisi】进行数据库查询.....
开始对参数【wangwu】进行数据库查询.....
开始对参数【zhangsan】进行数据库查询.....
完成对参数【lisi】进行数据库查询.....耗时4000毫秒
lisi:User [username=lisi, password=]
完成对参数【wangwu】进行数据库查询.....耗时6000毫秒
wangwu:User [username=wangwu, password=]
完成对参数【zhangsan】进行数据库查询.....耗时8000毫秒
zhangsan:User [username=zhangsan, password=]
耗时8002
可以看到,这儿查询是并发开始的,查询时间得到了极大的提升,瓶颈仅仅是最耗时的那个查询。代码很简单,但是需要理解。
在Java中也有一系列的例如java.util.concurrent.Future<V>,java.util.concurrent.Callable<V>,java.util.concurrent.Executors等一系列可以实现Future模式的类和接口,但是那些都是用起来简单,实现很复杂,重在理解。
我理解的Future模式的更多相关文章
- 深入理解[Future模式]原理与技术
1.Future模式 Future模式和多线程技术密切相关,可以说是利用多线程技术优化程序的一个实例. 在程序设计中,当某一段程序提交了一个请求,期望得到一个答复.但非常不幸的是,服务程序对这个请求的 ...
- 彻底理解Java的Future模式
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...
- 彻底理解Future模式
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...
- java Future 模式
考慮這樣一個情況,使用者可能快速翻頁瀏覽文件中,而圖片檔案很大,如此在瀏覽到有圖片的頁數時,就會導致圖片的載入,因而造成使用者瀏覽文件時會有停頓 的現象,所以我們希望在文件開啟之後,仍有一個背景作業持 ...
- 多线程:多线程设计模式(二):Future模式
一.什么是Future模型: 该模型是将异步请求和代理模式联合的模型产物.类似商品订单模型.见下图: 客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订 ...
- Java中的Future模式原理自定义实现
摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...
- 多线程设计模式(二):Future模式
一.什么是Future模型: 该模型是将异步请求和代理模式联合的模型产物.类似商品订单模型.见下图: 客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订 ...
- 并发模型(一)——Future模式
多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future.Master-Worker.Guard Susperionsion.不变.生产者-消费者 模式: jdk除了定义了若干并发 ...
- 13.多线程设计模式 - Future模式
多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...
随机推荐
- linux tomcat自动部署shell
#!/bin/bash #defined TOMCAT_HOME="/usr/java/tomcat/tomcat" TOMCAT_PORT=80 PROJECT ...
- CTE递归限制次数
CTE可以用来取递归,网上资料很多,这里就不再叙述了,今天遇到的需求是要限制只取2级,然后加了个临时的lev with tree as(select [CustomerID],[CustomerNam ...
- ceph常用指令
一.集群 1.启动一个ceph 进程 启动mon进程 service ceph start mon.node1 启动msd进程 service ceph start mds.node1 启动osd进 ...
- CodeForces 346A Alice and Bob (数学最大公约数)
题意:有一堆数,然后有两个人轮流从中取出两个数,这两个数的差的绝对值不在这个集合,然后把这个数放进这个集合,如果哪个人不能拿了,就是输了,问你谁赢. 析:当时连题意都没看好,以为拿出两个数,就不放回了 ...
- static 和final
1.static static关键字可以用来修饰类的变量,方法和内部类.static是静态的意思,也是全局的意思,它定义的东西属于全局,与类相关,不与具体实例相关.就是说它调用的时候,只是 ...
- URAL 1698. Square Country 5(记忆化搜索)
题目链接 题意 : 自守数的定义:如果某个数的平方的末尾几位数等于这个数,那么就称这个数为自守数.例如5*5=25,则5就是自守数.让你求不超过n位的自守数有多少 思路 : 实际上,自守数还有两个性质 ...
- HBASE与hive对比使用以及HBASE常用shell操作。与sqoop的集成
2.6.与 Hive 的集成2.6.1.HBase 与 Hive 的对比1) Hive(1) 数据仓库Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个双射关系,以方 ...
- [LeetCode 题解]: String to Interger (atoi)
Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. ...
- [Erlang06]在Erlang shell怎么在目录A下编译目录B下的文件,并把生成文件统一放置目录C?
问题描述: 我们想快速测试一个小功能,第一个反应就是打开Erl shell 直接输入,但是当想测试一个复杂的函数时,一般会写成一个*.erl文件,然后在shell下: cd(FileDir). c(F ...
- nexus3
Maven 介绍 Apache Maven 是一个创新的软件项目管理和综合工具. Maven 提供了一个基于项目对象模型(POM)文件的新概念来管理项目的构建,可以从一个中心资料片管理项目构建,报告和 ...