CompletableFuture,Future和RxJava的Observable之间的区别


193

我想知道的区别 CompletableFutureFutureObservable RxJava

我所知道的都是异步的,但是

Future.get() 阻塞线程

CompletableFuture 提供回调方法

RxJava Observable--- CompletableFuture与其他好处相似(不确定)

例如:如果客户端需要进行多个服务调用,并且当我们使用Futures(Java)时Future.get()将依次执行...希望了解它在RxJava中的效果如何。

并且文档http://reactivex.io/intro.html

使用Future来最佳地组合条件异步执行流是困难的(或者是不可能的,因为每个请求的延迟在运行时会有所不同)。当然可以这样做,但是很快就会变得复杂(因此容易出错),或者过早地在Future.get()上阻塞,这消除了异步执行的好处。

真的很想知道如何RxJava解决这个问题。我发现很难从文档中了解。


您已阅读每个文档吗?我完全不熟悉RxJava,但是文档一目了然。看来这两个期货没有特别的可比性。
FThompson'2

我经历了但无法得到与Java期货的不同...如果我错了,请纠正我
shiv455

可观察物与期货有何相似之处?
FThompson'2

2
想知道它与线程管理的不同之处在哪里?EX:Future.get()阻塞线程....如何在Observable中处理它?
shiv455'2

2
至少让我感到困惑...高水平的差异真的很有帮助!
shiv455'2

Answers:


278

期货

在Java 5(2004)中引入了期货。对于尚未完成的操作,它们基本上是占位符。操作完成后,Future将包含该结果。例如,操作可以是提交给ExecutorServiceRunnableCallable实例。操作的提交者可以使用该对象检查操作isDone(),还是使用阻塞的get()方法等待操作完成。Future

例:

/**
* A task that sleeps for a second, then returns 1
**/
public static class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        Thread.sleep(1000);
        return 1;
    }

}

public static void main(String[] args) throws Exception{
    ExecutorService exec = Executors.newSingleThreadExecutor();
    Future<Integer> f = exec.submit(new MyCallable());

    System.out.println(f.isDone()); //False

    System.out.println(f.get()); //Waits until the task is done, then prints 1
}

可完成的未来

Java 8(2014)中引入了CompletableFutures。实际上,它们是常规期货的演进,受到Guava库一部分的Google的Listenable Futures的启发。它们是期货,还使您可以将任务按链条在一起。您可以使用它们来告诉某个工作线程“执行某些任务X,完成后,再使用X的结果来完成另一件事”。使用CompletableFutures,您可以对操作的结果执行某些操作,而无需实际阻塞线程等待结果。这是一个简单的例子:

/**
* A supplier that sleeps for a second, and then returns one
**/
public static class MySupplier implements Supplier<Integer> {

    @Override
    public Integer get() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            //Do nothing
        }
        return 1;
    }
}

/**
* A (pure) function that adds one to a given Integer
**/
public static class PlusOne implements Function<Integer, Integer> {

    @Override
    public Integer apply(Integer x) {
        return x + 1;
    }
}

public static void main(String[] args) throws Exception {
    ExecutorService exec = Executors.newSingleThreadExecutor();
    CompletableFuture<Integer> f = CompletableFuture.supplyAsync(new MySupplier(), exec);
    System.out.println(f.isDone()); // False
    CompletableFuture<Integer> f2 = f.thenApply(new PlusOne());
    System.out.println(f2.get()); // Waits until the "calculation" is done, then prints 2
}

RxJava的

RxJava是Netflix创建的用于反应式编程的完整库。乍一看,它看起来类似于Java 8的stream。是的,只是功能更强大。

与Futures类似,RxJava可用于将一系列同步或异步操作串在一起以创建处理管道。与一次性使用的Futures不同,RxJava在零个或多个项目上工作。包括数量不限的无限流。多亏了令人难以置信的丰富操作员集,它也更加灵活和强大。

与Java 8的流不同,RxJava还具有背压机制,该机制使它可以处理处理管道的不同部分以不同的速率在不同的线程中运行的情况

RxJava的缺点是,尽管有可靠的文档,但是由于涉及的范例转换,它是一个具有挑战性的库。Rx代码也可能是调试的噩梦,尤其是在涉及多个线程的情况下,甚至更糟-如果需要背压。

如果您想了解它,则可以在官方网站上找到整的各种教程,以及官方文档Javadoc。您也可以看一下其中的一些视频,例如这段视频,简要介绍了Rx,还讨论了Rx和Futures之间的区别。

奖励:Java 9反应流

Java 9的反应式流(又名Flow API)是由各种反应式流库(例如RxJava 2Akka StreamsVertx)实现的一组接口。它们允许这些反应性库互连,同时保留所有重要的反压。


很好地给出Rx如何做到这一点的示例代码
Zinan Xing

因此,使用反应式流,我们可以在一个应用程序中混合使用RxJava,Akka和Vertx吗?
IgorGanapolsky

1
@IgorGanapolsky是的。
麦芽

在CompletableFutures中,我们使用回调方法,如果一个方法的输出是另一回调的输入,则这些回调方法也会阻塞。作为Future.get()调用的future块。为什么说Future.get()阻止了调用,而CompletableFutures没有阻止。请解释
-Deepak

1
@Federico当然。每个Future是一个占位符单一,可能会或可能不会有尚未完成的结果。如果再次执行相同的操作,则会得到一个新Future实例。RxJava处理可能随时出现的结果。因此,一系列操作可以返回一个可观察到的RxJava,它将输出大量结果。这有点像单个邮政信封和不断抽出邮件的气动管之间的区别。
麦芽

20

从0.9开始,我一直在使用Rx Java,现在是1.3.2,并且很快迁移到2.x,我在一个已经从事了8年工作的私人项目中使用了它。

没有这个库,我将不再编程。一开始我很怀疑,但这是您需要建立的另一种完整的心态。一开始就安静下来。我有时看了几个小时的大理石。

这只是一个实践问题,实际上是要了解流程(也就是可观察者与观察者的合同),一旦到达那里,就不愿这样做。

对我来说,该库并没有真正的缺点。

用例:我有一个包含9个仪表(cpu,mem,网络等)的监视器视图。启动视图时,视图将自己订阅系统监视器类,该类返回一个可观察的(时间间隔),其中包含9米的所有数据。它将每秒将新结果推送到视图(因此不轮询!!!)。该可观察的对象使用平面图同时(异步!)从9个不同的源中获取数据,并将结果压缩到一个新模型中,您的视图将在onNext()上获得。

你怎么会用期货,可完成商品等做这件事……祝你好运!:)

Rx Java为我解决了编程中的许多问题,并在某种程度上使工作变得更加轻松。

优点:

  • Statelss!(重要的事情,也许是最重要的)
  • 开箱即用的线程管理
  • 具有自己生命周期的构建序列
  • 一切都是可观察的,因此链接很容易
  • 减少编写代码
  • 类路径上的单个jar(非常轻巧)
  • 高度并发
  • 不再有回调地狱
  • 基于订户(消费者与生产者之间的紧密合同)
  • 背压策略(类似断路器)
  • 出色的错误处理和恢复
  • 非常好的文档(大理石<3)
  • 完全控制
  • 还有很多 ...

缺点:-难以测试


13
〜“ 我再也没有这个库了, ” RxJava最终对所有软件项目都是全部吗?
IgorGanapolsky

即使我没有异步事件流也有用吗?
Mukesh Verma
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.