我理解的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 ...
随机推荐
- DESC和 ACS
用 DESC 表示按倒序排序(即:从大到小排序)用 ACS 表示按正序排序(即:从小到大排序)
- vue相关操作
一: vue的安装 -安装node.js -vue脚手架 -vue create 项目名字 二:vue create 项目名字 用pycharm打开vue项目 -需要安装vue.js插件-settin ...
- java String,StringBuffer,StringBuilder区别及联系
String 字符串常量(不可变)StringBuffer 字符串变量(线程安全,可变) StringBuilder 字符串变量(非线程安全,性能优,可变) 简要的说, String 类型和 Stri ...
- 网络编程释疑之:单台服务器上的并发TCP连接数可以有多少
曾几何时我们还在寻求网络编程中C10K问题的解决方案,但是现在从硬件和操作系统支持来看单台服务器支持上万并发连接已经没有多少挑战性了.我们先假设单台服务器最多只能支持万级并发连接,其实对绝大多数应用来 ...
- C++11中的to_string
C++11之前,标准库没有提供数字类型转字符串的函数,需要借助sprintf.stringstream等,现在C++11提供了std::to_string函数,可以直接使用了: 点击(此处)折叠或打开 ...
- 将std::string当字节流使
string是C++标准定义的字符串类,它不但支持文本,而且支持二进制字节流.给一个string变量赋值有多种方法: 1) 拷贝构造函数 2) 等号赋值函数 3) append成员函数 4) push ...
- ACM 韩信点兵 、n的另一种阶乘、6174的问题
3.6174问题 描述 假设你有一个各位数字互不相同的四位数,把所有的数字从大到小排序后得到a,从小到大后得到b,然后用a-b替换原来这个数,并且继续操作.例如,从1234出发,依次可以得到4321- ...
- Linux-Linux基础入门
第一节 Linux系统简介 初步了解了什么是Linux系统,有何优势.与Windows系统有何不同,并了解Linux学习方法. 第二节 基本概念及概念 1.完成实验楼入门基础课程,共两个实验:(1)& ...
- js调试工具Console命令详解——转
一.显示信息的命令 <!DOCTYPE html> <html> <head> <title>常用console命令</title> < ...
- ARM启动代码中_main 与用户主程序main()的区别
1.1 问题描述 __main函数的作用是什么呀?1.2 问题剖析 __main函数是C/C++运行时库的一个函数,嵌入式系统在进入应用主程序之前必须有一个初始化的过程,使用__m ...