学而时习之,不亦说乎!

                             --《论语》

什么是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. Java Persistence with MyBatis 3(中文版) 前言

    对很多软件系统而言,保存数据到数据库和从数据库中检索数据是其工作流程中至关重要的一部分.在 Java 领域,有很多的实现了数据持久化层的工具和框架,它们每一个都有自己不同的实现方法.而 MyBatis ...

  2. java轻量级IOC框架Guice(转)

    出处:http://www.cnblogs.com/whitewolf/p/4185908.html Guice是由Google大牛Bob lee开发的一款绝对轻量级的java IoC容器.其优势在于 ...

  3. jenkins持续集成之Global Tool Configuration的配置

    Global Tool Configuration的配置过程: 1.点击系统管理2.点击 Global Tool Configuration3.必须配置: jdk git ant maven 1.点击 ...

  4. (1)WePHP 开启WePHP

    新建入口文件index.php,定义新项目的目录地址APP_PATH,引入WePHP项目入口文件 <?php define('APP_PATH','./index/'); require_onc ...

  5. 浅说Java反射机制

    工作中遇到,问题解决: JAVA语言中的反射机制: 在Java 运行时 环境中,对于任意一个类,能否知道这个类有哪些属性和方法? 对于任意一个对象,能否调用他的方法?这些答案是肯定的,这种动态获取类的 ...

  6. ArcGIS Runtime SDK for Android 授权(arcgis android 去除水印)

    ArcGIS Runtime SDK for Android 授权 ESRI中国北京 要下载和安装 ArcGIS Runtime SDK for Android,您需要注册开发者账户,进而便拥有了访问 ...

  7. .Net程序随系统开机启动(仿Foxmail托盘效果控制)

    对于使.NET程序随系统开机启动,最常用的可能就是向在注册表中注册开机启动项,或是建立Windows服务,使程序随系统启动而启动.这里以WinForm程序为例,测试Demo分享,同时附上对于程序托盘的 ...

  8. android之实现底部TabHost

    先说布局文件,如下:利用android:layout_alignParentBottom="true" 实现底部显示 <?xml version="1.0" ...

  9. 开源的 .Net Core MVC CMS 推荐

    简介 ZKEACMS Core 是基于 ZKEACMS 的 Asp.Net Core 版本. 架设环境: .Net Core 跨平台 Microsoft Sql Serverl 2008 或以上 .N ...

  10. codeVS 动态最大子段和

    题目链接:戳我 对于最大子段和,我们只需要维护四个变量--maxl,maxr,maxs,sum(分别表示区间最大前缀子段和,区间最大后缀子段和,区间最大子段和,区间所有数的和) 然后合并的时候是这样的 ...