最近的项目用到了多线程,发现java.util.concurrent.Future蛮好用的。
像平时,写多线程一般使用Thread/Runnable,直接扔给线程池执行就好了。但是遇到了一些需要获取线程执行结果的情况,就需要使用Callable。对于使用Callable的task,ExecutorService执行后会返回一个Future对象来传递执行结果。

那这个Future是怎么存放返回值的呢,这个Future有什么值得使用的地方呢。我查了一下,发现原来还专门有个Future模式。

Future模式

Future模式在请求发生时,会先产生一个Future凭证给发出请求的客户,它的作用就像是Proxy物件,同时,由一个新的执行线程持续进行目标物件的生成(Thread-Per-Message),真正的目标物件生成之后,将之设定至Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。

结合JDK的Future来看,就是你run线程后,你可以把线程的返回值赋给Future并返回一个Future对象。这时你可以立即拿到这个对象,然后进行下面的逻辑。但是如果你要get这个Future中的线程结果,就会被阻塞直到线程结束。

就相当于现在的期房,你把手续和钱都交上去了,就可以马上拿到合同,但只有合同没有房子。这个时候你已经是有房一族了,你可以先去买家电买装修(走下面的其他逻辑)。但是你要把家电和装修放进去,就必须等到房子完工(阻塞)。

这样有一个好处,就是你把处理任务交给线程并拿到那个future凭证,就可以去干别的事情了(同时线程也在处理),等你真正要用到这个线程返回值的时候再通过future来获取,这样能缩短阻塞的时间。

Demo

接下来,我们看看Future的一个demo,这个例子很简单,就是为表明线程提交处理后,future对象是立即返回的,紧接着“Ready”马上就打印“Give the future”了;而当调用future.get的时候就停下了,“Get the future”迟迟没有打印,被阻塞了,直到线程执行完毕为止。这里我让他睡了3秒钟,能看得更清楚。

public class FutureTest {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
System.out.println("Ready");
Future strFuture = executor.submit(new TaskTest());
System.out.println("Give the future"); System.out.println("Get the future : " + strFuture.get());
System.out.println("End");
executor.shutdown();
} public static class TaskTest implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(3000);
return "Hello World!";
}
}
}

Simulator

从future的应用能看出来,其实future实现的功能很简单,就是充当一个线程返回结果的寄存器,只是在获取结果的时候,检查线程是否已完成,还在处理则阻塞,否则返回结果。

下面我做了一个future的模拟实现:

首先future作为一个结果寄存器,就需要有个result来存放结果,另外需要一个isFinish来标记线程是否完成。当然我在set()的时候不仅给result赋值,还把isFinish标记成完成,因为一般返回值都在线程结束时赋值的,所以我也这么简化设计了。

测试使用上面的demo,运行结果也是一样的。只是我的这个future没有JDK那个优雅和健壮,那个还整合到ExecutorService,用起来更方便。


所以,还有请大神们指导,这样的future实现,是不是还有什么漏洞?

public class FutureSimulator {
private volatile T result;
private volatile boolean isFinish = false;
public void set(T result) {
this.result = result;
this.isFinish = true;
}
public T get() throws InterruptedException {
while (!isFinish) {
Thread.sleep(100);
}
return result;
} public static void main(String[] args) throws Exception {
FutureSimulator future = new FutureSimulator();
ExecutorService executor = Executors.newCachedThreadPool();
System.out.println("Ready");
executor.submit(new FutureTaskTest(future));
System.out.println("Give the future"); System.out.println("Get the future : " + future.get());
System.out.println("End");
executor.shutdown();
}
} class FutureTaskTest extends Thread {
private FutureSimulator future;
public FutureTaskTest(FutureSimulator future) {
this.future = future;
} @Override
public void run(){
try {
Thread.sleep(3000);
future.set("Hello World!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

[置顶] JDK-Future 模式和实现的更多相关文章

  1. [置顶] JDK工具(零)--简要介绍JDK1.6自带的42个工具

    Java的开发人员肯定都知道JDK的bin目录中有“java.exe”和“javac.exe”这两个命令行工具, 但并非所有的Java程序员都了解过JDK的bin目录之中其它命令行程序的作用. JDK ...

  2. [置顶] lvs-tun隧道模式搭建

    一.lvs直接路由原理 由于图片还要一张一张上传,可以到下面网站下载我的word版本: http://download.csdn.net/user/y0908105023 补充基础知识: OSI(Op ...

  3. [置顶] 单键模式的C++描述

    设计模式-单键(Signelton):其实单键的设计模式说来很简单,说的直白一点就是程序运行过程中保证只有一个实例在运行而已.在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例, ...

  4. [置顶] 使用严苛模式打破Android4.0以上平台应用中UI主线程的“独断专行”

    传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 已经有好一段时间没有关注Android应用方面的事情了:)最近单位来了一个Androi ...

  5. [置顶] JDK工具(一)–Java编译器javac

    1.概述    javac.exe: Java编译器,将Java源代码转换成字节码. 2.用法    javac <选项> <源文件> (使用过程中发现,javac <源 ...

  6. Future模式的学习以及JDK内置Future模式的源码分析

    并发程序设计之Future模式 一).使用Future模式的原因 当某一段程序提交了一个请求,期待得到一个答复,但服务程序对这个请求的处理可能很慢,在单线程的环境中,调用函数是同步的,必须等到服务程序 ...

  7. 【并发编程】Future模式及JDK中的实现

    1.1.Future模式是什么 先简单举个例子介绍,当我们平时写一个函数,函数里的语句一行行同步执行,如果某一行执行很慢,程序就必须等待,直到执行结束才返回结果:但有时我们可能并不急着需要其中某行的执 ...

  8. Future模式

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

  9. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

随机推荐

  1. apache hide index.php

    <Directory "D:/usr/local/www">    AllowOverride all    Options +FollowSymLinks +SymL ...

  2. Oracle学习之常见问题处理

    转自:http://blog.csdn.net/liusong0605/article/details/16349121 安装完oracle并启动服务后,通过sqlPlus无法登录,出现如下错误: s ...

  3. Effective MySQL之备份与恢复

    五分钟成为一名DBA 如果我们已经有了一个MySQL生产级系统,而该产品却没有MySQL备份策略,那么我们至少应该做些什么呢?在采取任何备份策略之前,有许多有关数据库大小和存储策略引擎的用法的预备知识 ...

  4. java之适配器模式

    interface Window {     public void open();     public void close();     public void activated();     ...

  5. 利用 onload 事件监控跨站资源

    用过 CSP 的都很郁闷,上报的只有违规的站点名,却没有具体路径.这是缺陷,还是特意的设计? 显然,CSP 是为安全定制的,里面的规范自然要严格制定,否则就会带来新的安全问题.如果支持详细路径的上报, ...

  6. MacOS Apache配置

    仅适用于apache 2.2版本   查看版本 sudo apachectl -v   启动服务器 sudo apachectl start 打开localhost,可以看到内容为“It works! ...

  7. 生成输出url

    继续使用前面的例子11-3URLTestDemo,修改Global.asax中的RegisterRoutes方法如下: public static void RegisterRoutes(RouteC ...

  8. android方向键被锁定的问题

    当虚拟机启动的时候,很多情况是旁边的方向键不能点击,处于一种被锁定的状态,解决办法如下: 找到   C:\Users\Administrator(你的用户名)\.android\avd\mm.adv( ...

  9. .NET(C#):XML序列化时派生类的处理

    原文 www.cnblogs.com/mgen/archive/2011/12/03/2275014.html 目录 1. 针对基类的XmlSerializer序列化派生类 2. 类内成员是派生类的序 ...

  10. windows中使用Git工具连接GitHub(配置篇)

    Git在源码管理领域目前占很大的比重了,而且开源的项目很多都转到GitHub上面了.例如:jQuery, reddit, Sparkle, curl, Ruby on Rails, node.js,  ...