`

当线程有了返回值——多线程设计之Future设计模式

阅读更多

先由一个例子引入什么是Future Pattern。

【例子】我去蛋糕店取蛋糕,下订单后,店员请我"请在天黑后再来店里取货",并给我一张提货单。在店员做蛋糕的时候,我可以陪MM逛街,看电影等,而不需要在蛋糕店外等候。黄昏后,我拿着这张提货单到蛋糕店来取货。店员说了声"先生,你的蛋糕好了",并把蛋糕给了我。

上面的例子就是Future Pattern的一个直观的使用例子。

  1. 假设有一个执行起来要花很久的方法(如做蛋糕),我们不需要等待结果完全出来了(蛋糕做好),而是获取一张替代的"提货单"。获取提货单不需要太长的时间,这个提货单就是Future参与者
  2. 获取Future参与者的线程,会在事后再去执行结果,就好像拿着提货单取蛋糕一样。如果已经有执行结果了,就马上拿到数据。如果还没有,则继续等待到执行结果完全出来为止。

上面就是一此完整的Future Pattern的运行模式。

下面提供一段范例程序。

首先介绍一下范例程序包含的一些类和接口:

  1. Main 说明:对Host送出请求,获取数据的类。
  2. Host 说明:对请求返回FutureData的类。
  3. Data 说明:表达数据访问方式的接口,FurureData与RealData都实现了这个接口。
  4. FurureData说明:RealData的提货单类,而RealData实例则有其他线程建立。
  5. RealData说明:表达实际数据的类,执行构造器要花一定的时间。

运行结果如下:

对结果的分析:

可以看到最开始Main线程开始后,三个请求线程,开始后马上就结束了。这一过程就好像有三个人去蛋糕店订蛋糕,立刻就拿到了提货单。这一过程体现在输出结果的1到7行。

这之后,三个人分别忙自己的事情去了,假设时间刚好为一下午(反映在程序中就是Main线程sleep的那2000毫秒),这期间蛋糕店的师傅也没闲着,加紧做蛋糕,最先做谁的蛋糕也完全随机,结果反映就是先做C,在A,最后是B。也就是输出结果的8到14行。

三个玩够了,肚子饿了。想起来蛋糕店还有蛋糕呢,于是去取蛋糕。这个时候蛋糕已经做完了,三个人顺利取走蛋糕回家。也就是结果的最后15到19行。

从程序来看,Future Pattern有几个必要的参与者。

  • Client(委托人)参与者,反映在程序中就是想Host发送请求的参与者,并得到VirtualData参与者,作为这个请求的结果(返回值),在实例程序中就是Main类。
  • Host(处理人)参与者,建立新的线程,开始建立RealData参与者,另一方面会对Client参与者,以(VirtualData参与者的形式)返回Future参与者。新的线程建立出来RealData后,会对Future参与者设置RealData参与者。示例Host就是Host。
  • VirtualData(虚拟数据)参与者,用来统一代表Future参与者和RealData参与者。在示例中就是Data接口。
  • RealData(实际数据)参与者,表示实际的数据,建立需要花一些时间,示例中RealData就是RealData。
  • Future(期货)参与者,Future是Host参与者传递给Client参与者,当做是RealData参与者"提货单"使用的参与者。Future参与者相对于Client参与者而言,可以进行VirtualData参与者的行为。

扩展思考:

1.吞吐量由提高吗?

对于我们的程序,对于单CPU的系统,CPU处理的总时间是一样的,因为计算机宏观并行,微观串行所决定。然而,如果加上I/O处理,如对硬盘的访问,大部分时间CPU只是等待工作结束而已,对于CPU,这部分时间是空闲时间,若能把空闲时间给其他的线程使用,那么相当于也提高了计算机的吞吐量。

2.响应性的提高?

对于此种模式,你不必等待某个工作的完成,你可以串行的干一些其他的工作。

3.实现异步?

使用此模式,通过"稍后在设置真正的处理结果",做到异步方法调用的返回值。

4.分离"准备返回值"和"使用返回值"

建立RealData的操作就是"准备方法的返回值",而调用getContent方法则是为了"使用方法的返回值"。如此,将调用方法的一系列动作,像慢动作播放一样逐一拆解,就可以把多线程当做道具来使用了。

Future设计模式是很有意思的一个模式,今天学习时很是喜欢,摘录一些段落加上自己的理解记录下来,与大家分享。

大部分摘自《Java多线程设计模式详解》一书。

分享到:
评论

相关推荐

    Java并发编程原理与实战

    Future设计模式实现(实现类似于JDK提供的Future).mp4 Future源码解读.mp4 ForkJoin框架详解.mp4 同步容器与并发容器.mp4 并发容器CopyOnWriteArrayList原理与使用.mp4 并发容器ConcurrentLinkedQueue原理与使用....

    java并发编程

    第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器...

    javaSE代码实例

    第16章 多线程——Java中的并发协作 343 16.1 线程的基本知识 343 16.1.1 多线程编程的意义 343 16.1.2 定义自己的线程 344 16.1.3 创建线程对象 345 16.1.4 启动线程 347 16.1.5 同时使用多个线程 ...

    龙果 java并发编程原理实战

    第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器...

    Java 并发编程原理与实战视频

    第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器...

    龙果java并发编程完整视频

    第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器...

    Python核心编程第二版(ok)

     10.3.3 带有多个except的try语句   10.3.4 处理多个异常的except语句   10.3.5 捕获所有异常   10.3.6 “异常参数”   10.3.7 在应用使用我们封装的函数   10.3.8 else子句   10.3.9 finally...

    Python核心编程第二版

     10.3.3 带有多个except的try语句   10.3.4 处理多个异常的except语句   10.3.5 捕获所有异常   10.3.6 “异常参数”   10.3.7 在应用使用我们封装的函数   10.3.8 else子句   10.3.9 finally...

Global site tag (gtag.js) - Google Analytics