线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascript,页面渲染等操作,当我们使用ajax向服务端发起请求,由于这个过程很慢,ajax的异步模式可以让我们无需一直等待服务端的响应,而在这个等待结果时间里做其他的事情,这个模式在线程技术力称之为Future模式。

  Future模式和我前面文章里说到的html5技术里的worker技术差不多,当我们一个程序执行流里某个操作特别耗时,我们可以另起一个线程专门执行这个繁琐耗时的任务,主线程则可以做其他的事情,下面是我自己找到的一个实现原生Future模式的代码,它主要参入者如下:

  TestMain.java:测试程序入口,主要是调用Client类,向Client发送请求;

  Client.java:返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData;

  Data.java:返回数据接口;

  FutureData.java:Future数据,构造快,但是是一个虚拟的数据,需要装配RealData;

  RealData.java:真实数据,其构造是比较慢的。

  详细代码如下:

Data接口:

package cn.com.xSharp.futurePattern.simple;

/**
* 数据接口
*/
public interface Data {
public String getData();
}

RealData代码:

package cn.com.xSharp.futurePattern.simple;

/**
* RealData是最终使用的数据,它构造很慢,因此用sleep来模拟
*/
public class RealData implements Data { protected final String result; public RealData(String param) {
StringBuffer sb = new StringBuffer();
for (int i = ;i < ;i++){
sb.append(param);
try {
Thread.sleep();
} catch (Exception e) {
e.printStackTrace();
}
}
result = sb.toString();
} @Override
public String getData() {
return result;
}
}

FutureData代码:

package cn.com.xSharp.futurePattern.simple;

public class FutureData implements Data {

    protected RealData realData = null;// FutureData对RealData的包装
protected boolean isReady = false; public synchronized void setRealData(RealData realData){
if (isReady){
return;
}
this.realData = realData;
isReady = true;
notifyAll();
} @Override
public synchronized String getData() {
while (!isReady){
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
return realData.result;
} }

Client代码:

package cn.com.xSharp.futurePattern.simple;

public class Client {

    public Data request(final String qryStr){
final FutureData futureData = new FutureData();
new Thread(){
public void run(){
RealData realData = new RealData(qryStr);
futureData.setRealData(realData);
}
}.start();
return futureData;
}
}

TestMain代码:

package cn.com.xSharp.futurePattern.simple;

public class TestMain {

    public static void main(String[] args) {
Client client = new Client();
Data data = client.request("xtq");
System.out.println("请求完毕!"); try {
for (int i = ;i < ;i++){
Thread.sleep();
System.out.println("可以做做其他的事情哦....");
} } catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("数据==:" + data.getData());
} }

执行结果:

 1 请求完毕!
2 可以做做其他的事情哦....
3 可以做做其他的事情哦....
4 可以做做其他的事情哦....
5 可以做做其他的事情哦....
6 可以做做其他的事情哦....
7 可以做做其他的事情哦....
8 可以做做其他的事情哦....
9 可以做做其他的事情哦....
10 可以做做其他的事情哦....
11 可以做做其他的事情哦....
12 可以做做其他的事情哦....
13 可以做做其他的事情哦....
14 数据==:xtqxtqxtqxtqxtqxtqxtqxtqxtqxtq

 JDK里在1.5之后提供了专门Future模式的实现,这里我使用FutureTask来实现Future模式。

  FutureTask在JDK文档里的解释:

  可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。 可使用 FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。 除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。

  下面是它的两个构造函数:

FutureTask(Callable<V> callable)
          创建一个 FutureTask,一旦运行就执行给定的 Callable。
FutureTask(Runnable runnable, V result)
          创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。

  这里我首先使用第二个构造函数Runnable实现Future模式,代码如下:

package cn.com.futuretest;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask; public class FutureRunnable implements Runnable{
private Result result; // 操作的数据,模拟一个计算需要很长时间的数据 /* 初始化数据 */
public FutureRunnable(Result result) {
this.result = result;
} @Override
public void run() {
try {
for (int i = ;i < ;i++){
Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
result.setData(result.getData() + ":" + "futureRunnable" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
Result r = new Result("xSharp");// 构造测试数据
FutureRunnable futureCallable = new FutureRunnable(r);// 初始化runnable
FutureTask<Result> task = new FutureTask<Result>(futureCallable, r);
// 构造固定大小为一个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool();
// 执行线程
executorService.execute(task);
System.out.println("执行完毕!"); try {
for (int i = ;i < ;i++){
Thread.sleep();
System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} try {
System.out.println("打印结果是:" + task.get().getData());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally{
System.exit();
}
}
}

 执行结果: 

执行完毕!
数据还在计算中等待中,你可以做别的事情0
数据还在计算中等待中,你可以做别的事情1
数据还在计算中等待中,你可以做别的事情2
数据还在计算中等待中,你可以做别的事情3
数据还在计算中等待中,你可以做别的事情4
数据还在计算中等待中,你可以做别的事情5
数据还在计算中等待中,你可以做别的事情6
数据还在计算中等待中,你可以做别的事情7
数据还在计算中等待中,你可以做别的事情8
数据还在计算中等待中,你可以做别的事情9
数据还在计算中等待中,你可以做别的事情10
数据还在计算中等待中,你可以做别的事情11
数据还在计算中等待中,你可以做别的事情12
数据还在计算中等待中,你可以做别的事情13
数据还在计算中等待中,你可以做别的事情14
打印结果是:xSharp:futureRunnable0:futureRunnable1:futureRunnable2:futureRunnable3:futureRunnable4:futureRunnable5:futureRunnable6:futureRunnable7:futureRunnable8:futureRunnable9

 接下来我使用Callable<V> 接口实现FutureTask,代码如下:

 package cn.com.futuretest;

 import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask; public class FutureCallable implements Callable<Result>{ private Result result; // 操作的数据,模拟一个计算需要很长时间的数据 /* 初始化数据 */
public FutureCallable(Result result) {
this.result = result;
} @Override
public Result call() throws Exception {
try {
for (int i = ;i < ;i++){
Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
result.setData(result.getData() + ":" + "futureCallable" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
} public static void main(String[] args) {
long start = System.currentTimeMillis();
Result r = new Result("xSharp");// 构造测试数据
FutureCallable callable = new FutureCallable(r);
FutureTask<Result> task = new FutureTask<Result>(callable);
// 构造固定大小为一个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool();
// 执行线程
executorService.execute(task);
System.out.println("执行完毕!");
long curr01 = System.currentTimeMillis();
System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
try {
for (int i = ;i < ;i++){
Thread.sleep();
System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} try {
System.out.println("打印结果是:" + task.get().getData());
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally{
System.exit();
}
} }

执行结果如下:

执行完毕!
任务提交后的耗时:6毫秒
数据还在计算中等待中,你可以做别的事情0
数据还在计算中等待中,你可以做别的事情1
数据还在计算中等待中,你可以做别的事情2
数据还在计算中等待中,你可以做别的事情3
数据还在计算中等待中,你可以做别的事情4
数据还在计算中等待中,你可以做别的事情5
打印结果是:xSharp:futureCallable0:futureCallable1:futureCallable2:futureCallable3:futureCallable4:futureCallable5:futureCallable6:futureCallable7:futureCallable8:futureCallable9
总耗时:1010毫秒

这里我对代码做了一些调整,一个是加上了执行时间的统计,一个是我将干其他事情的程序执行时间变短,小于了线程本身执行的时间,这么做的目的是想和下面的程序对比,下面的代码当我执行线程后没有做其他的操作,而是直接获取线程执行的结果,具体代码如下:

package cn.com.futuretest;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask; public class NioFutureCallable implements Callable<Result> { private Result result; // 操作的数据,模拟一个计算需要很长时间的数据 /* 初始化数据 */
public NioFutureCallable(Result result) {
this.result = result;
} @Override
public Result call() throws Exception {
try {
for (int i = ;i < ;i++){
Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
result.setData(result.getData() + ":" + "NioFutureCallable" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
} public static void main(String[] args) {
long start = System.currentTimeMillis();
Result r = new Result("xSharp");// 构造测试数据
NioFutureCallable callable = new NioFutureCallable(r);
FutureTask<Result> task = new FutureTask<Result>(callable);
// 构造固定大小为一个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool();
// 执行线程
executorService.execute(task);
System.out.println("执行完毕!");
long curr01 = System.currentTimeMillis();
System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒"); /* 第一次获取返回数据 */
try {
System.out.println("第一次打印结果是:" + task.get().getData());
long curr02 = System.currentTimeMillis();
System.out.println("第一次获取结果耗时:" + (curr02 - start) + "毫秒");
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
} try {
for (int i = ;i < ;i++){
Thread.sleep();
System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} try {
System.out.println("第二次打印结果是:" + task.get().getData());
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally{
System.exit();
} } }

执行结果如下:

 1 执行完毕!
2 任务提交后的耗时:7毫秒
3 第一次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
4 第一次获取结果耗时:1009毫秒
5 数据还在计算中等待中,你可以做别的事情0
6 数据还在计算中等待中,你可以做别的事情1
7 数据还在计算中等待中,你可以做别的事情2
8 数据还在计算中等待中,你可以做别的事情3
9 数据还在计算中等待中,你可以做别的事情4
10 数据还在计算中等待中,你可以做别的事情5
11 数据还在计算中等待中,你可以做别的事情6
12 数据还在计算中等待中,你可以做别的事情7
13 数据还在计算中等待中,你可以做别的事情8
14 数据还在计算中等待中,你可以做别的事情9
15 第二次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
16 总耗时:2012毫秒

我们看到当我们直接获取结果时候,整个主线程都被阻塞了,直到结果返回后才会执行下面的后续操作,这也就是说如果计算还没结束,我们就想获取结果这样整个执行流程都将被阻塞,这点在我们合理使用Future模式时候很重要。

  除了使用FutureTask实现Future模式,我们还可以使用ExecutorService的submit方法直接返回Future对象,Future就和我前面设计的原生Future类似,当我们开始调用时候返回的是一个虚拟结果,其实实际的计算还没有结束,只有等待吗一会儿后结果才会真正的返回,代码如下:

package cn.com.futuretest;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class RetFutureCallable implements Callable<Result>{ private Result result; // 操作的数据,模拟一个计算需要很长时间的数据 public RetFutureCallable() {
result = new Result("xSharp");
} @Override
public Result call() throws Exception {
try {
for (int i = ;i < ;i++){
Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
result.setData(result.getData() + ":" + "RetFutureCallable" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
} public static void main(String[] args) {
long start = System.currentTimeMillis();
RetFutureCallable callable = new RetFutureCallable();
// 构造固定大小为一个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool();
// 执行线程
Future<Result> r = executorService.submit(callable);
System.out.println("执行完毕!");
long curr01 = System.currentTimeMillis();
System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
try {
for (int i = ;i < ;i++){
Thread.sleep();
System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} try {
System.out.println("打印结果是:" + r.get().getData());
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally{
System.exit();
}
} } 

执行结果如下:

 1 执行完毕!
2 任务提交后的耗时:5毫秒
3 数据还在计算中等待中,你可以做别的事情0
4 数据还在计算中等待中,你可以做别的事情1
5 数据还在计算中等待中,你可以做别的事情2
6 数据还在计算中等待中,你可以做别的事情3
7 数据还在计算中等待中,你可以做别的事情4
8 数据还在计算中等待中,你可以做别的事情5
9 打印结果是:xSharp:RetFutureCallable0:RetFutureCallable1:RetFutureCallable2:RetFutureCallable3:RetFutureCallable4:RetFutureCallable5:RetFutureCallable6:RetFutureCallable7:RetFutureCallable8:RetFutureCallable9
10 总耗时:1006毫秒

转自:http://www.cnblogs.com/sharpxiajun/p/5608663.html

线程技术 ☞ Future模式的更多相关文章

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

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

  2. 线程笔记:Future模式

    线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascri ...

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

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

  4. Java线程池(Callable+Future模式)

    转: Java线程池(Callable+Future模式) Java线程池(Callable+Future模式) Java通过Executors提供四种线程池 1)newCachedThreadPoo ...

  5. java future模式 所线程实现异步调用(转载

    java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...

  6. 架构师养成记--9.future模式讲解

    什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...

  7. Future模式

    Future模式简介 Future模式有点类似于网上购物,在你购买商品,订单生效之后,你可以去做自己的事情,等待商家通过快递给你送货上门.Future模式就是,当某一程序提交请求,期望得到一个答复.但 ...

  8. 闲谈Future模式-订蛋糕

    一. Future模式简介 Future有道翻译:n. 未来:前途:期货:将来时.我觉得用期货来解释比较合适.举个实际生活中例子来说吧,今天我女朋友过生日,我去蛋糕店准备给女朋友定个大蛋糕,超级大的那 ...

  9. java Future 模式

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

随机推荐

  1. python学习之 -mysql 连接和db_config配置

    最近学习python,记录下自己写学习python的代码和心得,自己写了一个使用python mysql 的查询语句和做的一个db_config.py 配置信息. 1.db_config.py 配置文 ...

  2. 修改app名字

    一张图说明问题 如果没有成功clean一下,或者卸载掉原有的重新生成一下 如果要修改路径名和工程名有个复杂的方法 http://blog.sina.com.cn/s/blog_a42013280101 ...

  3. elasticsearch 性能优化

    #系统默认的最大打开文件数的限制 vi /etc/security/limits.conf   *     -       nproc          50240    *     -       ...

  4. 在Site Settings下找不到Navigation标签

    有时候我们可能找不到Navigation标签, 仅仅在Look and Feel下面看到"Quick launch" 如何才能找到我们想要的"Navigation&quo ...

  5. cut 命令

    今天看到cut拿来取参数也是很方便的. cut -d = -f 2 -d表示分隔符 -f参数是分隔符算第几个参数

  6. Squares<哈希>

    Description A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-d ...

  7. Delphi控件的显示内容与显示边框是两回事

    没有内容,不代表没有边框.比如设计期一个空的TImage仍是有边框的. if (csOpaque in image1.ControlStyle) then ShowMessage('不透明')else ...

  8. How to add alias on Mac(It's common for most system)

    Since these files are hidden you will have to do an ls -a to list them. If you don't have one you ca ...

  9. UVa 10256 凸包简单应用

    题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  10. MAVEN 工程打包resources目录外的更多资源文件

    首先,来看下MAVENx项目标准的目录结构: 一般情况下,我们用到的资源文件(各种xml,properites,xsd文件等)都放在src/main/resources下面,利用maven打包时,ma ...