学而时习之,不亦说乎!

                             --《论语》

什么是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模式的更多相关文章

  1. 深入理解[Future模式]原理与技术

    1.Future模式 Future模式和多线程技术密切相关,可以说是利用多线程技术优化程序的一个实例. 在程序设计中,当某一段程序提交了一个请求,期望得到一个答复.但非常不幸的是,服务程序对这个请求的 ...

  2. 彻底理解Java的Future模式

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  3. 彻底理解Future模式

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  4. java Future 模式

    考慮這樣一個情況,使用者可能快速翻頁瀏覽文件中,而圖片檔案很大,如此在瀏覽到有圖片的頁數時,就會導致圖片的載入,因而造成使用者瀏覽文件時會有停頓 的現象,所以我們希望在文件開啟之後,仍有一個背景作業持 ...

  5. 多线程:多线程设计模式(二):Future模式

    一.什么是Future模型: 该模型是将异步请求和代理模式联合的模型产物.类似商品订单模型.见下图: 客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订 ...

  6. Java中的Future模式原理自定义实现

    摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...

  7. 多线程设计模式(二):Future模式

    一.什么是Future模型: 该模型是将异步请求和代理模式联合的模型产物.类似商品订单模型.见下图: 客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订 ...

  8. 并发模型(一)——Future模式

    多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future.Master-Worker.Guard Susperionsion.不变.生产者-消费者 模式: jdk除了定义了若干并发 ...

  9. 13.多线程设计模式 - Future模式

    多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...

随机推荐

  1. jQuery自动截取文字长度,超过部分

    <html> <head>     <meta charset="utf-8">     <script src="js/jqu ...

  2. Python 简单模块学习

    1. openpyxl / xlrd / xlwt  => 操作Excel 文件(xlsx格式) => xlrd + xlwt : 只能操作xls文件,分别负责读写, 暂时不讨论 => ...

  3. windows server2012如何开启mysql远程登录

    开发的首要任务就是要搭建起自己的服务器,下面主要是我这搭建记录下 我的各种环境 服务器为Windows server2012  安装的MySQL数据的版本是5.6.10 ,64位.当然了版本对于安装没 ...

  4. 用阿里巴巴官方给Jmeter开发的Dubbo sampler取样器进行dubbo接口测试【图解剖析】

    自:https://blog.csdn.net/cyjs1988/article/details/84258046 [一]Dubbo sampler下载地址: 该插件支持jmeter 3.2及3.2以 ...

  5. C++编译器之间的不同性能

    C++编译器之间的不同性能 编译器就是将“高级语言”翻译为“机器语言(低级语言)”的程序.一个现代编译器的主要工作流程:源代码 (source code) →预处理器 (preprocessor) → ...

  6. 解决VS2010中工具箱里没有WPM

    我前段时间要用到MS的WPM,但苦于找不到解决不了,无奈重装后一样的情况我的win7 旗舰版版+VS2010旗舰版.在控制面板里找到多媒体重新关闭并从新打开,就OK啦..记得要重启哦...

  7. WPF判断当前窗体是否为模态

    WPF判断当前窗体是否为模态   1.使用System.Windows.Interop.ComponentDispatcher.IsThreadModal来判断 参照:https://social.m ...

  8. jenkins+windows+springboot+.net项目自动化部署图文教程

    之前一直在linux中使用jenkins部署程序,正好现在的项目包括了winfrom程序,所以需要部署到windows系统中 jenkins官网:https://jenkins.io/ 下载之后运行j ...

  9. ZKEACMS 2.2.1 正式发布,更多特性等您来发现

    前言 如果你还不知道ZKEACMS,不妨先了解一下. ASP.NET MVC 开源建站系统 ZKEACMS 推荐,从此网站“拼”起来 官方地址:http://www.zkea.net/zkeacms ...

  10. ASP.NET Core URL Rewrite中间件

    URL重写是基于一个或多个预置规则修改请求URL的行为.URL重写在资源位置和访问地址之间创建了一种抽象,这样二者之间就减少了紧密的联系.URL重写有多种适用的场景: 临时或永久移动或替换服务器资源, ...