Future介绍
用过Java并发包的朋友或许对Future (interface) 已经比较熟悉了,其实Future 本身是一种被广泛运用的并发设计模式,可在很大程度上简化需要数据流同步的并发应用开发。
Future模式可以简单的看成是 Proxy 模式 与 Thread-Per-Message 模式 的结合,在Proxy模式中,用一个Proxy来代替真正的目标(Subject)生成,目标的生成可能是费时的,例如在开启一个内嵌图片的文件中,希望程式能尽快完成开启文件的动作,并显示一个可接受的画面给使用者看,在还不需要看到图片的页面中先使用Proxy代替真正的图片载入,只有在真正需要看到图片时,才由Proxy物件载入真正的图片。
考虑这样一个情况,使用者可能快速翻页浏览文件中,而图片档案很大,如此在浏览到有图片的页数时,就会导致图片的载入,因而造成使用者浏览文件时会有停顿的现象,所以我们希望在文件开启之后,仍有一个背景作业持续载入图片,如此使用者在快速浏览页面时,所造成的停顿可以获得改善。
Future模式在请求发生时,会先产生一个Future物件给发出请求的客户,它的作用就像是Proxy物件,而同时间,真正的目标物件之生成,由一个新的执行绪持续进行(即Thread-Per-Message),真正的目标物件生成之后,将之设定至Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。
这里就以java.util.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式订阅接口,其等待数据的可用性不是由订阅者决定,而在于发布者何时发布或更新数据。因此,相对于标准的Future,Promise接口一般会多出一个set()或fulfill()接口。
可复用的Future
常规的Future是一次性的,也就是说当你获得了异步的处理结果后,Future对象本身就失去意义了。但经过特殊设计的Future也可以实现复用,这对于可多次变更的数据显得非常有用。例如前面提到的淘宝分布式订阅框架所提供的Future式接口,它允许多次调用waitNext()方法(相当于Future.get()),每次调用时是否阻塞取决于在上次调用后是否又有数据发布,如果尚无更新,则阻塞直到下一次的数据发布。这样设计的好处是,接口的使用者可以在其任何合适的时机,或者直接简单的在独立的线程中通过一个无限循环响应订阅数据的变化,同时还可兼顾其它定时任务,甚至同时等待多个Future。简化的例子如下:
for (;;) {
schedule = getNextScheduledTaskTime();
while(schedule > now()) {
try {
data = subscription.waitNext(schedule - now());
processData(data);
} catch(Exception e) {...}
}
doScheduledTask();
}
分享到:
相关推荐
【31 凭票取餐—Future模式详解】 在Java并发编程中,Future模式是一种常见的设计模式,它允许主线程在不阻塞的情况下启动一个异步任务,然后在需要时获取任务的结果。Future模式的灵感来源于现实生活中的场景,如...
Future模式核心思想是异步调用,这里具体实现代码,其思想是:网上订了一个货之后,他会立即返回下好订单给你,你可以去做其他事,不用再一直等这个货物到达,以后有时间,货物到了,你就可以拿这个订单,去取货。...
Spring Boot对Future模式的支持使得开发者可以更方便地在应用程序中实现异步处理,从而提高系统的并发性能和响应速度。在实际开发中,当遇到需要执行耗时操作或复杂计算时,我们可以利用多线程来提升效率,而Future...
老生常谈java中的Future模式 在 Java 中,Future 模式是一种常用的设计模式,用于处理并发编程中的多线程问题。在这个模式中,线程 A 需要等待线程 B 的结果,但线程 A 不需要一直等待线程 B,可以先拿到一个未来的...
Future模式的优势在于它能够将异步的数据驱动自然地融入到顺序流程中,使得并发代码保持简洁和优雅。与回调驱动相比,Future模式避免了回调函数中可能出现的线程安全问题,同时提供了更好的顺序流程控制。回调虽然...
"Future" 在IT行业中通常指的是未来的趋势、技术发展或预测。在这个上下文中,"Future" 可能是指新兴的IT技术,比如云计算、人工智能(AI)、大数据、物联网(IoT)以及区块链等。这些技术都在不断地重塑我们的数字...
在Swift编程语言中,"Future" 是一个设计模式,它被用于处理异步操作和结果的响应。这个概念源于函数式编程,已经被许多现代编程语言所采纳,包括Swift。"Future" 实现了一种机制,使得开发者可以在异步任务完成之前...
这些模式包括4种内燃机/并联混合模式、2种纯电池电力模式(PHEV)、1种电子连续可变传输模式(ECVT)。 在功率流动方面,Future Hybrid X Mode可以实现从内燃机到电动机的无缝切换,以及在电力驱动和内燃机驱动之间...
在Java编程领域,NIO(New Input/Output)和Future模式是两个重要的概念,它们分别在并发处理和异步操作中发挥着关键作用。这里我们将深入探讨这两个知识点,并结合压缩包中的"nioStudy"文件来解析它们的应用。 一...
总的来说,`future-architect-vuls`是一款强大而实用的开源工具,它以无代理的模式解决了Linux系统的漏洞扫描难题,提高了安全运维的效率,值得广大Linux用户和管理员关注和使用。在日常的系统管理中,合理利用此...
Future<String> responseFuture = restTemplate.getForEntity(url, String.class, new MyResponseCallback()); ``` 在以上代码中,`query()`是模板方法,`UserRowMapper`是回调接口,用于映射查询结果;`...
5. 模式识别算法:让计算机能够从经验中学习,并能够对新的数据进行分类识别。 6. 数据压缩算法:在不损失数据质量的前提下,减少文件大小以便存储和传输。 7. 数据库一致性算法:数据库在进行更新操作时如何保持...
Java 中的 Future 模式允许我们提交一个异步任务并获取其结果,而无需直接管理线程。我们可以在提交任务后继续执行其他操作,稍后再通过 Future 对象获取结果。这种方式提高了程序的并发性和灵活性。 在实际应用中...
- **Future**:未来模式,提供异步计算的结果。 - **Read-Write Lock**:读写锁模式,允许多个读取者同时访问,但只允许一个写入者。 - **Two-phase Termination**:两阶段终止模式,确保所有线程都能优雅地终止。 -...
该文档标题为“Fundamental design issues for the future Internet”,即“未来互联网的基础设计问题”,这表明文档将讨论未来互联网发展过程中可能遇到的关键技术问题。描述中提到,尽管互联网最初的设计目的是...
2. **异步编程增强**:可能增强了对`asyncio`库的支持,提供更方便的异步编程模式。 3. **错误修复**:修复了一些已知的bug,提高了库的稳定性和可靠性。 4. **性能优化**:可能在某些关键操作上进行了性能优化,如...
下一代网络(The Future X Network)是贝尔实验室的作品,聚焦于网络技术的未来发展方向和变革。本书深入剖析了未来网络环境所涉及的关键技术,系统架构的创新以及系统层面的突破点,旨在构建一个全新的数字化未来。书...
综上所述,增强分析作为新一代的数据分析模式,不仅极大地简化了数据分析的过程,降低了对专业技能的要求,同时也为企业带来了更高效、准确的决策支持。对于数据与分析领导者而言,积极拥抱这一变革,制定合理的战略...