未来和承诺之间有什么区别?

时间:2013-01-26 21:56:22

标签: java concurrency future promise

FuturePromise之间的区别是什么? 它们都像未来结果的占位符,但主要区别在哪里?

9 个答案:

答案 0 :(得分:119)

根据this discussionPromise最终被称为CompletableFuture以包含在Java 8中,its javadoc解释说:

  

可以明确完成的未来(设置其值和状态),并且可以用作CompletionStage,支持在完成时触发的依赖函数和动作。

列表中还给出了一个例子:

f.then((s -> aStringFunction(s)).thenAsync(s -> ...);

请注意,最终的API略有不同,但允许类似的异步执行:

CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);

答案 1 :(得分:113)

(到目前为止,我对答案并不完全满意,所以这是我的尝试......)

我认为凯文赖特的评论(“你可以做出承诺,由你决定保留它。当别人让你做出承诺时,你必须等待,看看他们是否在未来尊重它”)很好地总结了它,但是一些解释可能很有用。

Futures and promises是非常相似的概念,不同之处在于,future是一个只读容器,用于尚未存在的结果,而promise可以写入(通常只有一次)。 Java 8 CompletableFuture 和Guava SettableFuture可以被认为是promises,因为它们的值可以设置(“完成”),但是它们也实现了Future接口,因此没有区别。客户。

未来的结果将由“其他人”设置 - 由异步计算的结果。注意FutureTask - 一个经典的未来 - 必须如何用Callable或Runnable初始化,没有无参数构造函数,Future和FutureTask都是从外部读取的( FutureTask的set方法受到保护)。该值将从内部设置为计算结果。

另一方面,承诺的结果可以随时由“你”(或实际上由任何人)设置,因为它有一个公共的setter方法。 CompletableFuture和SettableFuture都可以在没有任何任务的情况下创建,并且可以随时设置它们的值。您向客户端代码发送承诺,并在以后按照您的意愿完成。

请注意,CompletableFuture不是一个“纯粹”的承诺,它可以像FutureTask一样使用任务进行初始化,其最有用的功能是处理步骤的无关链接。

另请注意,promise不必是future的子类型,也不必是同一个对象。在Scala中,Future对象由异步计算或不同的 Promise对象创建。在C ++中,情况类似:生产者使用promise对象,消费者使用future对象。这种分离的好处是客户无法设定未来的价值。

SpringEJB 3.1都有一个AsyncResult类,类似于Scala / C ++的承诺。 AsyncResult确实实现了Future,但这不是真正的未来:Spring / EJB中的异步方法通过一些背景魔法返回一个不同的只读Future对象,客户端可以使用第二个“真实”未来来访问结果。

答案 2 :(得分:90)

我知道已经接受了答案,但我想加上我的两分钱:

TLDR:Future和Promise是异步操作的两个方面:消费者/来电者生产者/实施者

作为异步API方法的来电,您将获得 Future 作为计算结果的句柄。你可以,例如在其上调用get()以等待计算完成并检索结果。

现在想一想这个API方法是如何实现的:实现者必须立即返回Future。一旦计算完成,他们就负责完成未来(他们知道因为它正在实施调度逻辑;-))。他们将使用 Promise / CompletableFuture 来做到这一点:立即构建并返回CompletableFuture,然后调用{{1计算完成后。

答案 3 :(得分:36)

我将举例说明什么是Promise以及如何在任何时候设置其值,与Future相反,该值只能读取。

假设你有一个妈妈而且你向她要钱。

现在,你欺骗你的妈妈给你一个最终捐赠的承诺,她给你这个承诺对象,但她并没有真正轻率地实现它:

Supplier<Integer> momsPurse = ()-> {

        try {
            Thread.sleep(1000);//mom is busy
        } catch (InterruptedException e) {
            ;
        }

        return 100;

    };


ExecutorService ex = Executors.newFixedThreadPool(10);

CompletableFuture<Integer> promise =  
CompletableFuture.supplyAsync(momsPurse, ex);

你很高兴,你要感谢你的妈妈:

promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));

但是你的父亲干涉并且通常会摒弃妈妈的计划并完成承诺(设定其价值!)的贡献远远小于父亲那样,非常坚决,而妈妈正在慢慢打开她的钱包(注意Thread.sleep(...) )):

promise.complete(10); 

输出是:

Thank you mom for $10

妈妈的承诺已经创建,但等待一些“完成”事件。

CompletableFuture<Integer> promise...

你创造了这样的活动,接受了她的承诺并宣布你的计划,感谢你的妈妈:

promise.thenAccept...

此时妈妈开始打开她的钱包......但很慢......

父亲干涉得更快,完成了承诺而不是你的妈妈:

promise.complete(10);

您是否注意到我明确写过的执行人? 有意思的是,如果你使用默认隐式执行器(commonPool)而父亲不在家,只有妈妈带着她的“慢钱包”,那么她的承诺只会完成,如果程序的生命时间超过妈妈需要从钱包。我的意思是默认执行程序以“守护进程”的方式运行。我还没有找到关于这个事实的好描述......

答案 4 :(得分:7)

不确定这是否可以作为答案但是当我看到其他人对某人所说的内容时,您可能看起来需要对这两个概念进行两个单独的抽象,以便其中一个(Future)只是一个另一个(Promise)的只读视图......但实际上这不是必需的。

例如,看看如何在javascript中定义promises:

https://promisesaplus.com/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

重点是使用then方法的可组合性,如:

asyncOp1()
.then(function(op1Result){
  // do something
  return asyncOp2();
})
.then(function(op2Result){
  // do something more
  return asyncOp3();
})
.then(function(op3Result){
  // do something even more
  return syncOp4(op3Result);
})
...
.then(function(result){
  console.log(result);
})
.catch(function(error){
  console.log(error);
})

使异步计算看起来像同步:

try {
  op1Result = syncOp1();
  // do something
  op1Result = syncOp2();
  // do something more
  op3Result = syncOp3();
  // do something even more
  syncOp4(op3Result);
  ...
  console.log(result);
} catch(error) {
  console.log(error);
}

非常酷。 (不像 async-await 那样酷,但 async-await 只是删除了样板 ....然后(function(result){.... 来自它。)

实际上他们的抽象作为承诺构造函数

非常好
new Promise( function(resolve, reject) { /* do it */ } );

允许您提供两个回调,可用于成功完成Promise或出错。因此,只有构造Promise的代码才能完成它,并且接收已构造的Promise对象的代码具有只读视图。

如果解决并且拒绝是受保护的方法,那么继承可以实现上述目标。

答案 5 :(得分:2)

Future接口中没有set方法,只有get方法,因此它是只读的。 关于CompletableFuture,本文可能会有所帮助。 completablefuture

答案 6 :(得分:2)

对于客户端代码,Promise用于在结果可用时观察或附加回调,而Future是等待结果然后继续。从理论上讲,任何可能与期货有关的事情都可以通过承诺完成,但由于风格的差异,所产生的不同语言承诺的API使链接更容易。

答案 7 :(得分:0)

this example中,您可以了解如何在Java中使用Promises。 用于创建异步调用序列:

doSomeProcess()
    .whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
    .whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
    .map(String::toLowerCase)
    .mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
    .whenResult(s -> System.out.println(s));

答案 8 :(得分:0)

FuturePromise 是未知结果的代理对象

Promise 完成一个 Future

  • Promise - 未知结果的写入/生产者。
  • Future - 未知结果的读取/消费者。它有下一个状态:待定、已完成、已取消
//Future has a reference to Promise
Future -> Promise

作为producer,我promise对某事负责

作为检索 consumerpromise,我希望在 future 中得到结果。在 future 中,我可以使用 promise 或拒绝它

对于 Java CompletableFutures 它是一个 Promise 因为你可以设置结果并且它也实现了 Future