JDK-Future 模式和实现

来源:互联网 发布:淘宝先装修后上架 编辑:程序博客网 时间:2024/06/08 04:41
        最近的项目用到了多线程,发现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 {@Overridepublic 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;}@Overridepublic void run(){try {Thread.sleep(3000);future.set("Hello World!");} catch (InterruptedException e) {e.printStackTrace();}}}
原创粉丝点击