有时候,在并发编程中使用哪种抽象,尤其是Java 8之后,会出现混乱。有一些相互竞争的API允许您以一种干净的方式来表达异步计算。本节将对所有这些内容进行比较,以帮助您选择适合该作业的工具。可用的抽象包括以下内容:
- CompletableFuture
Java 8中引入的CompletableFuture对java.util.concurrent包中的Future有了更强大的扩展。CompletableFuture允许在Future 完成或失败时注册异步回调,而不是阻塞并等待结果。但真正的优势来自组合和转换功能,类似于Observable.map()和flatMap()提供的功能。尽管在标准JDK中引入,但是在标准Java库中没有一个类依赖或使用CompletableFuture。它是完全可用的,但并不是很好地集成到Java生态系统中。安靠193页的“A Short Introduction to CompletableFuture ”
- Parallel Stream
就像CompletableFutures一样,java.util.stream中的Stream在JDK 8中引入。Streams 是一种声明一系列操作的方式,如映射、筛选等。流中的所有操作都是惰性的,直到使用了终端操作,例如collect()或reduce()。另外,JDK可以自动将一些操作并行化到所有可用的内核上,这听起来很有说服力。并行流承诺在多核上,透明的映射、过滤,甚至对大型数据集进行排序。流通常是由集合生成的,但也可以在动态和无限的情况下创建。
- rx.Observable
一个Observable 代表着一连串的事件在不可预知的时刻出现的流。它可以表示0、1、固定或无限多个事件,可以立即或随时间发射。Observable可以通过Completion或Error通知而终止。你现在应该对Observable很熟悉了
- rx.Single
当RxJava成熟时,很明显,一个只表示一个结果的特定的类型是有益的。Single类型是一个流,它要么以一个值结束,要么以Error结束。从这个意义上说,它很像一个CompletableFuture ,但是Single 是惰性的,这意味着他们在订阅之前不会开始计算。在202页的“Observable versus Single”中描述了Single。
- rx.Completable
有时,我们仅仅为了副作用而调用某个特定的计算,而不期待任何结果。发送电子邮件或在数据库中存储记录是此类操作的示例,它们涉及I/O(这可以从异步处理中获益),但不返回任何有意义的结果。传统上,在这样的场景中使用CompletableFuture <Void>或者 Observable<Void>。然而,更具体的Completable类型更好地表达了异步计算而没有结果返回的意图。Completable可以在并发执行中通知Completion或Error,就像所有其他Rx类型一样,他也是惰性的。
显然,还有其他方式表示异步计算,例如:
- 来自Reactor的Flux和Mono。这些类型在某种程度上类似于Observable和Single。
- Guava的ListenableFuture
但是,我们将通过将其限制在JDK和RxJava中来保持我们的选择列表。在我们继续之前,让我声明一下,如果您的应用程序已经非常一致地使用了CompletableFuture,那么您应该坚持使用它。由CompletableFuture提供的一些API虽然有点笨拙,但是一般来说,这个类提供了对响应式编程的很好的支持。此外,我们可以期望越来越多的框架能够利用和使用这种方式来支持它。在第三方库中支持RxJava更加困难,因为它需要额外的依赖,而CompletableFuture 是Java的一部分。