最近的项目用到了多线程,发现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. MyEclipse 免安装版制作

    前言:以MyEclipse6.0为例,安装目录,例如如d:\java\MyEclipse6.0 (1)新建MyEclipse 6.0.bat文件 新建位置:当前MyEclipse根目录 文件内容: s ...

  2. Spring Jdbc使用like模糊查询

    public List<WfConfigMVO> queryList(WfConfigMVO wfConfig) throws SysException { StringBuffer sq ...

  3. 有关extern的用法

    1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同.作为一种欲与C兼容的语言, C++保留了一部分过程式 ...

  4. this .运算符 和 [] 运算符

    首先看这个  这两个运行结果是不一样的 前两个是3  后面是10 var length = 10; var arr = [function(){console.log(this.length);},2 ...

  5. MockObject

    http://www.mockobjects.com/ http://jmock.org/download.html https://jakarta.apache.org/cactus/mock_vs ...

  6. lambda表达式和闭包

    lambda表达式和闭包 熟悉的Javascript或者Ruby的同学,可能对另一个名词:闭包更加熟悉.因为一般闭包的示例代码,长得跟lambda差不多,导致我也在以前很长一段时间对这两个概念傻傻分不 ...

  7. Android使用XML全攻略(1)

    Android使用XML全攻略(1)    Android 是针对移动设备的一种新兴的开源操作系统和 SDK.借助它,您可以创建功能强大的移动应用程序.当您的应用程序可以访问 Web 服务时,其吸引力 ...

  8. 害人的VS2008,manifest导致“应用程序配置不正确,应用程序未能启动”

    在VC++2008的项目中,如何显示地指定要使用的C++库的版本? 开发环境:VS2008 SP1 + Win2003 SP2         因为我的VS2008安装了SP1补丁,所以有了9.0.3 ...

  9. 迭代器(iterators)

    1.迭代器的概念 迭代器是一种抽象的设计概念.在设计模式中,迭代器模式定义为:提供一种方法,使之能够依序访问某个容器中所含的各个元素,而又无需暴露该容器的内部组织结构. 迭代器可以看做一种行为类似指针 ...

  10. 【每周一译】愚蠢的指标:Java中使用最多的关键字

    此翻译纯属个人爱好,由于水平所限,翻译质量可能较低.网络上可能存在其它翻译版本,原文地址:http://blog.jooq.org/2013/08/26/silly-metrics-the-most- ...