`
san_yun
  • 浏览: 2639625 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

理解Future

    博客分类:
  • java
 
阅读更多

什么是Future?

用过Java并发包的朋友或许对Future (interface)已经比较熟悉了,其实Future本身是一种被广泛运用的并发设计模式,可在很大程度上简化需要数据流同步的并发应用开发。在一些领域语言(如Alice ML)中甚至直接于语法层面支持Future。

这里就以java.concurrent.Future为例说一下Future的具体工作方式。Future对象本身可以看作是一个显式的引用,一个对异步处理结果的引用。由于其异步性质,在创建之初,它所引用的对象可能还并不可用(比如尚在运算中,网络传输中或等待中)。这时,得到Future的程序流程如果并不急于使用Future所引用的对象,那么它可以做其它任何想做的事儿,当流程进行到需要Future背后引用的对象时,可能有两种情况:

希望能看到这个对象可用,并完成一些相关的后续流程。如果实在不可用,也可以进入其它分支流程。
"没有你我的人生就会失去意义,所以就算海枯石烂,我也要等到你。"(当然,如果实在没有毅力枯等下去,设一个超时也是可以理解的)

对于前一种情况,可以通过调用Future.isDone()判断引用的对象是否就绪,并采取不同的处理;而后一种情况则只需调用get()或
get(long timeout, TimeUnit unit)通过同步阻塞方式等待对象就绪。实际运行期是阻塞还是立即返回就取决于get()的调用时机和对象就绪的先后了。(如下图所示)





简单而言,Future模式可以在连续流程中满足数据驱动的并发需求,既获得了并发执行的性能提升,又不失连续流程的简洁优雅。


与其它并发设计模式的对比

除了Future外,其它比较常见的并发设计模式还包括"回调驱动(多线程环境下)"、"消息/事件驱动(Actor模型中)"等。

回调是最常见的异步并发模式,它有即时性高、接口设计简单等有点。但相对于Future,其缺点也非常明显。首先,多线程环境下的回调一般是在触发回调的模块线程中执行的,这就意味着编写回调方法时通常必须考虑线程互斥问题;其次,回调方式接口的提供者在本模块的线程中执行用户应用的回调也是相对不安全的,因为你无法确定它会花费多长时间或出现什么异常,从而可能间接导致本模块的即时性和可靠性受影响;再者,使用回调接口不利于顺序流程的开发,因为回调方法的执行是孤立的,要与正常流程汇合是比较困难的。因此回调接口适合于在回调中只需要完成简单任务,并且不必与其它流程汇合的场景。

上述这些回调模式的缺点恰恰正是Future的长项。由于Future的使用是将异步的数据驱动天然的融入顺序流程中,因此你完全不必考虑线程互斥问题,Future甚至可以在单线程的程序模型(例如协程)中实现(参见下文将要提到的"Lazy Future")。另一方面,提供Future接口的模块完全不必担心像回调接口那样的可靠性问题和可能对本模块的即时性影响。

另一类常见的并发设计模式是"消息(事件)驱动",它一般运用在Actor模型中:服务请求者向服务提供者发送消息,然后继续进行后续不依赖服务处理结果的任务,在需要依赖结果前终止当前流程并记录状态;在等到回应消息后根据记录的状态触发后续流程。这种基于状态机的并发控制虽然比回调更适合于有延续性的顺序流程,但开发者却不得不将连续流程按照异步服务的调用切断为多个按状态区分的子流程,这样又人为的增加了开发的复杂性。运用Future模式可以避免这个问题,不必为了异步调用而打碎连续的流程。但是有一点应当特别注意:Future.get()方法可能会阻塞线程的执行,所以它通常无法直接融入常规的Actor模型中。(基于协程的Actor模型可以较好的解决这个冲突)

Future的灵活性还体现在其同步和异步的自由取舍,开发者可以根据流程的需要自由决定是否需要等待[Future.isDone()],何时等待[Future.get()],等待多久[Future.get(timeout)]。比如可以根据数据是否就绪而决定要不要借这个空档完成点其它任务,这对于实现"异步分支预测"机制是相当方便的。


Future的衍生

除了上面提到的基础形态之外,Future还有丰富的衍生变化,这里就列举几个常见的。


Lazy Future
与一般的Future不同,Lazy Future在创建之初不会主动开始准备引用的对象,而是等到请求对象时才开始相应的工作。因此,Lazy Future本身并不是为了实现并发,而是以节约不必要的运算资源为出发点,效果上与Lambda/Closure类似。例如设计某些API时,你可能需要返回一组信息,而其中某些信息的计算可能会耗费可观的资源。但调用者不一定都关心所有的这些信息,因此将那些需要耗费较多资源的对象以Lazy Future的形式提供,可以在调用者不需要用到特定的信息时节省资源。

另外Lazy Future也可以用于避免过早的获取或锁定资源而产生的不必要的互斥。

Promise
Promise可以看作是Future的一个特殊分支,常见的Future一般是由服务调用者直接触发异步处理流程,比如调用服务时立即触发处理或Lazy Future的取值时触发处理。但Promise则用于显式表示那些异步流程并不直接由服务调用者触发的情景。例如Future接口的定时控制,其异步流程不是由调用者,而是由系统时钟触发,再比如配置中心客户端提供的Future式订阅接口(Subscription),其等待数据的可用性不是由订阅者决定,而在于发布者何时发布或更新数据。因此,相对于标准的Future,Promise接口一般会多出一个set()或fulfill()接口。

可复用的Future
常规的Future是一次性的,也就是说当你获得了异步的处理结果后,Future对象本身就失去意义了。但经过特殊设计的Future也可以实现复用,这对于可多次变更的数据显得非常有用。例如配置中心客户端所提供的Future式接口(Subscription),它允许多次调用waitNext()方法(相当于Future.get()),每次调用时是否阻塞取决于在上次调用后是否已经有数据发布,如果尚无更新,则阻塞直到下一次的数据发布。这样设计的好处是,接口的使用者可以简单的在单线程中通过一个无限循环响应订阅数据的变化,同时还可兼顾其它定时任务,甚至同时等待多个Future。简化的例子如下:

for (;;) {
  schedule = getNextScheduledTaskTime();

  while(schedule > now()) {
    try {
      data = subscription.waitNext(schedule - now());
      processData(data);
    } catch(Exception e) {...}
  }

  doScheduledTask();
}

分享到:
评论

相关推荐

    JAVA语言版本LeedCode刷题

    - 异步编程:理解Future和Callable接口,以及ExecutorService的使用。 4. **LeetCode刷题策略** - 题目分类:LeetCode题目按难度和主题分类,可以根据自己的水平和需求选择合适的题目。 - 动态规划:常见算法之...

    Python库 | aiommy-0.0.2-py3-none-any.whl

    3. **Future对象**:理解Future对象在异步编程中的作用,它是如何作为结果容器,连接回调函数和协程的。 4. **asyncio的常用API**:学习如`create_task`、`run`、`wait`、`gather`等API的使用,以便于管理并发任务...

    2018尚硅谷Java培训视频链接_Java基础阶段

    - Future与Callable:理解Future接口和Callable接口的区别,学习FutureTask类的使用。 #### Java——NIO - **NIO概述**: - NIO简介:介绍NIO(New I/O)的基本概念及其与传统IO的区别。 - 缓冲区(Buffer):...

    netty框架演示

    - **异步编程**:理解Future和Promise的概念,学会编写异步非阻塞的代码。 - **处理异常**:了解Netty的异常处理机制,如channelInactive和exceptionCaught方法。 - **性能调优**:学习如何配置EventLoopGroup,...

    caffe-future

    压缩包中的"caffe-future"文件可能包含了配置文件、模型权重、样例数据集以及相关的脚本,这些都是理解并运行Caffe-Future的关键元素。 总的来说,Caffe-Future是深度学习在语义分割领域的重要实践,它的出现使得...

    future-0.18.3

    同时,文档的改进和示例代码的更新也会帮助开发者更好地理解和利用这个库。 总的来说,"future-0.18.3"是一个旨在简化Python 2到Python 3迁移过程的库,通过提供兼容性工具和特性,让开发者能够在不同的Python版本...

    Android-Future基于Kotlin协同程序的简单的monadic未来实现

    首先,让我们深入理解什么是"Future"。在编程领域,Future通常表示一个尚未完成但预期将来的计算结果。在Java中,`java.util.concurrent.Future`接口就是这样的一个概念,它允许我们注册回调或者查询结果是否已经...

    Java 7并发编程实战手册

    4. **Future与Callable**:理解Future接口和Callable接口的工作原理,以及如何使用它们来获取异步计算的结果。 5. **CountDownLatch、CyclicBarrier**:这些同步辅助类在控制多个线程间的协作方面非常有用,通过...

    future2.1.6

    在Python编程语言中,`...理解和熟练使用`futures`可以帮助开发者编写出更加高效、响应迅速的Python程序。在实际项目中,根据任务的性质选择合适的执行器,以及正确地使用`Future`对象的方法,是提升代码性能的关键。

    使用future处理并发1

    在Python编程中,处理并发和异步操作是提高程序效率的关键。`future`是一个核心概念,特别是在`concurrent.futures`模块和`asyncio`包中。...在编写Python代码时,理解这些特性可以帮助我们设计出更高效的并发程序。

    The Future of Retail

    The Future of Retail - To the extent that there are two distinct sides to the argument, the position of Offline-to-Online (O2O) advocates is that, as more offline retailers are closing, brick-and-...

    Nine Algorithms That Changed the Future

    这些算法不仅帮助我们理解了当今的计算机技术,也为我们指明了未来技术的发展方向。 书中详细介绍了如下算法: 1. 搜索引擎索引:如何从海量的信息中快速定位到用户所需的内容。 2. PageRank算法:一种由谷歌公司...

    Python库 | future_fstrings-0.4.1.tar.gz

    首先,我们需要理解f-string(格式化字符串字面值)是Python 3.6引入的一种新的字符串格式化方式,它允许开发者在字符串中直接嵌入表达式,提供了一种简洁、高效的字符串格式化方法。然而,f-string仅在Python 3.6及...

    联想服务future leader宣讲会现场笔试

    【联想服务Future Leader宣讲会现场笔试】是一场针对潜在领导人才的招聘活动,旨在寻找具有技术...通过解答这些问题,候选人有机会展示自己的全面能力和对联想业务的理解,从而有机会成为联想服务团队的Future Leader。

    Future

    "Future"字体可能被设计成程序员友好的,具有良好的字符间距、高度和宽度,使得代码更易于阅读和理解。一些代码编辑器和IDE(集成开发环境)允许用户自定义字体,"Future"可能会是其中的一个选项。 总之,"Future...

    future-0.18.1.tar.gz

    "Future" 是一个在Python编程语言中广泛使用的库,它主要关注异步编程和线程交互,特别是对于处理I/O密集型任务时提高程序效率。...通过研究源代码和文档,开发者可以更好地理解和利用这个库来构建高效的异步应用程序。

    future-1.0.0.tar.gz

    2. **文档**:可能有`docs/`目录,包含README、API参考、示例等,帮助用户理解和使用库。 3. **测试**:`tests/`目录下的测试脚本,确保库的正确性。 4. **安装脚本**:如`setup.py`,用于安装库到用户的Python环境...

    future-0.18.2.tar.gz

    在安装和使用这个库时,应确保遵循官方文档的指示,并理解如何正确导入和使用`future`模块中的类和函数,以充分利用其潜力。 总的来说,"future-0.18.2.tar.gz"对于那些希望在Python 2和Python 3之间实现无缝切换的...

    开源项目-future-architect-vuls.zip

    在实际操作中,用户需要熟悉基本的Go编程和构建命令,以及理解Linux系统的概念。 总的来说,"future-architect-vuls"是一个实用的工具,它简化了Linux系统安全审计的过程,为安全管理提供了有力的支持。开源社区的...

    future-0.15.0.tar.gz

    首先,我们要理解"Future"这个概念。在Python中,"Future"对象代表了一个异步操作的结果,它可以是正在进行的、已完成的,或者是被取消的。"Future"提供了一种统一的方式来处理这些异步操作,使得编写异步代码更加...

Global site tag (gtag.js) - Google Analytics