14.Java中的Future模式

jdk1.7.0_79 

  本文实际上是对上文《13.ThreadPoolExecutor线程池之submit方法》的一个延续或者一个补充。在上文中提到的submit方法里出现了FutureTask,这不得不停止脚步将方向转向Java的Future模式。

  Future是并发编程中的一种设计模式,对于多线程来说,线程A需要等待线程B的结果,它没必要一直等待B,可以先拿到一个未来的Future,等B有了结果后再取真实的结果。

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);    //主线程需要callable线程的结果,先拿到一个未来的Future
System.out.println(future.get());    //有了结果后再根据get方法取真实的结果,当然如果此时callable线程如果没有执行完get方法会阻塞执行完,如果执行完则直接返回结果或抛出异常

  也就是说,Future它代表一个异步计算的结果。

  上面就代表了Future模式的执行原理,根据网上的例子,我们可以来自己实现一个Future模式。

1 package com.future;
2
3 /**
4  * 数据结果
5  * Created by yulinfeng on 6/18/17.
6  */
7 public interface Data {
8     String getResult() throws InterruptedException;
9 }
 1 package com.future;
 2
 3 /**
 4  * 结果的真实计算过程
 5  * Created by yulinfeng on 6/18/17.
 6  */
 7 public class RealData implements Data {
 8     protected String data;
 9
10     public RealData(String data) {
11         try {
12             System.out.println("正在计算结果");
13             Thread.sleep(3000);     //模拟计算
14         } catch (InterruptedException e) {
15             e.printStackTrace();
16         }
17         this.data = data + “ world”;
18     }
19
20     public String getResult() throws InterruptedException {
21         return data;
22     }
23 }
 1 package com.future;
 2
 3 /**
 4  * 真实结果RealData的代理
 5  * Created by yulinfeng on 6/18/17.
 6  */
 7 public class FutureData implements Data {
 8     RealData realData = null;   //对RealData的封装,代理了RealData
 9     boolean isReady = false;    //真实结果是否已经准备好
10
11     public synchronized void setResultData(RealData realData) {
12         if (isReady) {
13             return;
14         }
15         this.realData = realData;
16         isReady = true;
17         notifyAll();    //realData已经被注入到了futureData中,通知getResult方法
18     }
19
20     public synchronized String getResult() throws InterruptedException {
21         if (!isReady) {
22             wait();     //数据还未计算好,阻塞等待
23         }
24         return realData.getResult();
25     }
26 }
 1 package com.future;
 2
 3 /**
 4  * Client主要完成的功能包括:1. 返回一个FutureData;2.开启一个线程用于构造RealData
 5  * Created by yulinfeng on 6/18/17.
 6  */
 7 public class Client {
 8
 9     public Data request(final String string) {
10         final FutureData futureData = new FutureData();
11
12         /*计算过程比较慢,单独放到一个线程中去*/
13         new Thread(new Runnable() {
14
15             public void run() {
16                 RealData realData = new RealData(string);
17                 futureData.setResultData(realData);
18             }
19         }).start();
20
21         return futureData;  //先返回一个“假”的futureData
22     }
23 }
 1 /**
 2  * 负责调用Client发起请求,并使用返回的数据。
 3  * Created by yulinfeng on 6/18/17.
 4  */
 5 public class Main {
 6     public static void main(String[] args) throws InterruptedException {
 7         Client client = new Client();
 8         System.out.println("准备计算结果");
 9         Data data = client.request("hello");    //立即返回一个“假”的futureData,可以不用阻塞的等待数据返回,转而执行其它任务
10         System.out.println("执行其它任务");
11         Thread.sleep(3000);     //模拟执行其它任务
12         System.out.println("数据的计算结果为:" + data.getResult());
13     }
14 }

  仔细阅读以上程序对Future模式的实现不难发现,Future模式是异步请求和代理模式的结合。当然在JDK中已经为我们实现好了Future模式。

  修改RealData类:

 1 package com.future;
 2
 3 import java.util.concurrent.Callable;
 4
 5 /**
 6  * 结果的真实计算过程
 7  * Created by yulinfeng on 6/18/17.
 8  */
 9 public class RealData2 implements Callable<String> {
10     protected String data;
11
12     public RealData2(String data) {
13         this.data = data;
14     }
15     public String call() throws Exception {
16         try {
17             System.out.println("正在计算结果");
18             Thread.sleep(2000);     //模拟计算结果
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22         this.data = data + " world";
23         return data;
24     }
25 }

  修改Main测试类:

 1 package com.future;
 2
 3 import java.util.concurrent.ExecutionException;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 import java.util.concurrent.Future;
 7
 8 /**
 9  * 负责调用Executor的submit,并使用返回的数据。
10  * Created by yulinfeng on 6/18/17.
11  */
12 public class Main2 {
13
14     public static void main(String[] args) throws InterruptedException, ExecutionException {
15         ExecutorService client = Executors.newSingleThreadExecutor();   //类似Client
16         System.out.println("准备计算结果");
17         Future<String> data = client.submit(new RealData2("hello"));    //类似Client.request
18         System.out.println("执行其它任务");
19         Thread.sleep(3000);
20         System.out.println("数据的计算结果为:" + data.get());
21     }
22 }

  现在回到上文还未解决完的AbstractExecutorService#submit方法。

  类比上面的Client#request方法,在Client#request中先创建一个FutureData实例,而在AbstractExecutorService#submit中则是创建一个FutureTask实例,接着Client#request新创建一个线程用于异步执行任务,并直接返回FutureData,而在AbstractExecutorService#submit中同样也将任务交给了execute方法,并直接返回FutureTask。当然JDK中Future模式的实现更为复杂。

  在《12.ThreadPoolExecutor线程池原理及其execute方法》中我们讲解了execute方法,在ThreadPoolExecutor$Worker#runWorker方法第1145行中是对task任务的调用:

//ThreadPoolExecutor$Worker#runWorker
task.run();

  submit调用execute以执行run方法,实际执行的是FutureTask中的run方法。在FutureTask#run中,可以看到对任务Callable类型的task异步的执行,以及结果的保存。

时间: 2024-11-03 22:56:28

14.Java中的Future模式的相关文章

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

摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个箱子有获取数据和装载数据的机制),至于箱子中的数据是通过另开一个线程去获取的,隔一段时间之后,当我们想要获取箱子中的数据的时候,就直接从箱子中拿就行了,一般情况下,由于获取到箱子之后到我需要从箱子中拿取数据应该已经过了一段时间(因为做其他一些操作),正是这一段时间,数据通过其它线程已经 Future

java中的工厂模式

java中的工厂模式,个人理解是:要想制作一个汽车,则必须有轮子,发动机,座椅等. 1.创建一个接口,并且使得轮子,发动机,座椅三个实现类实现这个接口. 2.创建一个工厂,生成基于给定信息的实体类的对象. 1 public class 零件工厂{ 2 3 4 public Shape 获得零件(String 零件名称){ 5 if(零件名称== null){ 6 return null; 7 } 8 if(零件名称.equalsIgnoreCase("轮子")){ 9 return n

Java之多线程中的Future模式

应用场景:线程A需要线程B的执行结果,但没必要一直等待线程B执行完,这个时候可以先拿到未来的Future对象,等线程B执行完再来取真实结果. 定义RealData真实数据类,其构造函数很慢,是用户最后需要使用的数据, static class RealData<T> { protected T result; public RealData(T result) { this.result = result; } public T getResult() { return result; } }

Java中的迭代器模式

迭代器模式 提供一种方式去访问一个容器元素中的各个对象,而又不暴露该对象的内部细节. 迭代器模式的结构 1.迭代器角色 负责定义访问和遍历元素的接口 2.具体迭代器角色 实现迭代器接口,并要记录遍历中的当前位置 3.容器角色 负责提供创建具体迭代器角色的接口 4.具体容器角色 实现创建具体迭代器角色的接口,这个具体迭代器角色与该容器的结构相关 为什么需要迭代器模式 列举一个简单的示例,遍历ArrayList.LinkedList.HashSet中各个元素: 1 public static voi

Java中的代理模式

1.什么是代理模式 代理模式:就是为其他对象提供一种代理以控制对这个对象的访问. 代理可以在不改动目标对象的基础上,增加其他额外的功能(扩展功能). 举个例子来说明代理的作用: 一般我们想邀请明星来当我们的代言人,我们并不能直接联系到明星,而是通过其经纪人,来告诉经纪人我们需要和明星进行合作,然后通过经纪人来转达给明星.,明星只需要做好代言工作就好,其他繁琐的事情就交于经纪人就可以.这里的经经纪人就是一个代理对象,明星就是一个目标对象. 用图表示如下: 2.三种代理模式  2.1 静态代理 静态

JAVA中的策略模式strategy

原文出自:http://ttitfly.iteye.com/blog/136467 1. 以一个算术运算为例,传统做法为: java 代码 package org.common; public class Calculate { public String getResult(float a,float b,char c){ float add = a+b; float sub = a-b; float mult = a*b; float division = a/b; switch(c){ c

胡博君解Java中简单工厂模式

为什么要用简单工厂模式: 我们都知道程序是分开的,客户端中有程序,服务器端有程序,一般来说我们写的main方法中的程序都是在客户端电脑中的,按照我们学习的时候喜欢的写法: //一般来说这个程序都是在客户电脑中,俗称调用者 public  class  Text{ public static void main(String[] args) { Person  p  =  new  Person(); p.getInfo(); } } //一般这个程序都在服务器中,俗称被调用者,而且是可以修改的

你了解Java中的Future吗?

原文:https://www.jianshu.com/p/b8952f07ee5d 1.概述 在本文中,我们将了解Future.自Java 1.5以来一直存在的接口,在处理异步调用和并发处理时非常有用. 2.创建Future 简单地说,Future类表示异步计算的未来结果 - 这个结果最终将在处理完成后出现在Future中. 让我们看看如何编写创建和返回Future实例的方法. Future接口是长时间运行方法异步处理的理想选择.这使我们能够在等待Future封装的任务完成时执行一些其他事情.

关于java中生产者消费者模式的理解

在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify()方法是持有相同的对象锁来唤醒休眠的线程,使其具有抢占cpu的资格.可以理解同步方法,同步方法的对象锁就是谁调用这个方法,这个对象就是对象锁. 根据李兴华老师的视频讲解,建立一个生产者类,一个消费者类,还有一个Info类,贴上代码: 1.生产者类 package com.company; /** *