我理解的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 ...
随机推荐
- Dubbo的配置及启动
Tomcat+Dubbo安装 1.将tomcat的webapps目录下的所有文件清空,讲Dubbo管理控制台的程序dubbo-admin-2.5.3.war放 到webapps中,并且解压命名为ROO ...
- UVa 12342 Tax Calculator (水题,纳税)
今天在uva看到一个水题,分享一下. 题意:制定纳税的总额,有几个要求,如果第一个180000,不纳,下一个300000,纳10%,再一个400000,纳15%,再一个300000,纳20%,以后的纳 ...
- Exception (1) Understanding Exception Handling
When an exception is thrown, it cannot be ignored--there must be some kind of notification or termin ...
- 编写高质量代码改善C#程序的157个建议——建议131:用PascalCasing命名公开元素
建议131:用PascalCasing命名公开元素 开放给调用者的属性.字段和方法都应该采用PascalCasing命名方法,比如: class Person { public string Firs ...
- 【小梅哥FPGA进阶教程】第十一章 四通道幅频相可调DDS信号发生器
十一.四通道幅频相可调DDS信号发生器 本文由山东大学研友袁卓贡献,特此感谢 实验目标 实现多通道可调信号发生器 实验平台 芯航线FPGA核心板.ADDA模块 实验现象 实现基于FPGA的多通道可调信 ...
- Android-监听操作系统短信
想要访问Android操作系统的ContentProvider就需要明白以下原理: 在Android操作系统里面的 /packsges/目录: apps: 很多的系统应用,例如:联系人,浏览器,音乐播 ...
- uwsgi启动报错WARNING: Can't find section "uwsgi" in INI configuration file autotestsite_uwsgi.ini
提示配置文件头部找不到 [uwsgi] 解决: 在最上方加上[uwsgi],有时候明明有标识,但是还是提示,那就再加一个
- Windows解决多版本python执行pip3时出错AttributeError: module 'enum' has no attribute 'IntFlag'?
摘要: 本机装有python2.7和python3.6,执行pip和pip2时没有问题,执行pip3时提示: C:\Users\>pip3 Traceback (most recent call ...
- Dapper扩展Dapper.Common框架 Linq To Sql 底层源码.net ORM框架
源代码:https://github.com/1448376744/Dapper.CommonNUGET: Dapper.CommonQQ群:642555086 一.基本结构,此处可用委托,或动态代理 ...
- django model项目外操作
方法1: python manage.py shell 然后import对应的model并操作 方法2: 新建py脚本 import sys import os pwd = os.path.dirna ...