最近的项目用到了多线程,发现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. 浅谈Spring(三)

    一.基础Spring的标准测试 1.导入spring与junit继承的jar 2.引入注解 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfig ...

  2. As Easy As A+B

    Problem Description These days, I am thinking about a question, how can I get a problem as easy as A ...

  3. sublime模式下开启vim并修改esc

    首先我用的是sublime text2 sublime下开启vim模式: 在Preference -> Setting-User里面加上 "ignored_packages" ...

  4. H3C交换配置PBR最佳实践

    简要说明 PBR算是比较常用的功能,需要我们去掌握一下 配置步骤简要 配置BFD 配置track 配置acl 配置policy-based-route 在接口上面应用policy-based-rout ...

  5. 删除windows7保留分区

    在系统里以管理员运行CMD.exe键入diskpartsel disk 0  (select 选择硬盘)list vol  (查看卷)sel vol 0  (选择卷,0为保留分区)inactive ( ...

  6. UPPH、UPH

    UPPH=units Per Hour Per Person,单位小时人均产能,是公司作为衡量员工工作绩效的重要指标. UPPH是衡量员工单位时间工作量的一种绩效指标. UPPH计算方式如下: UPP ...

  7. mongodb初体验

    最近关注大数据,自然会关注到nosql数据库,其中当然是mongodb. nosql数据库大多是k,v数据库,这也不是新鲜的名词了,berkerly DB已经存在很多年了,现在属于oracle. 具体 ...

  8. Euromonitor 2013年奢侈品报告精选 |华丽志

    Euromonitor 2013年奢侈品报告精选 |华丽志 Euromonitor 2013年奢侈品报告精选

  9. SQL存储过程动态查询数据区间

    以前经常看到人查询数据库采用left join及case方式,一条一条的枚举查询整个数据的数据区间方法可行,但是数据一但很大,枚举就死悄悄,在网上查看,几乎全是照抄case ,left join枚举无 ...

  10. 纯代码 自己主动屏幕适配iPhone button

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bmdlc2hpaHVhdGlhbg==/font/5a6L5L2T/fontsize/400/fil ...