未来与承诺的区别

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

根据这个讨论 , Promise最终被称为CompletableFuture包含在Java 8中, 它的javadoc解释说:

未来可以明确地完成(设定其价值和状态),并可以用作完成阶段,支持完成时触发的相关function和操作。

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

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

请注意,最终的API稍有不同,但允许类似的asynchronous执行:

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

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

我想凯文·赖特(Kevin Wright)的评论( “你可以做出一个承诺,取决于你,当别人让你承诺,你必须等待,看看他们是否在未来承认)”,总结得很好,但一些解释可能是有用的。

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

未来的结果将由“别人”设置 – 由asynchronous计算的结果。 注意FutureTask是一个经典的未来,它必须使用Callable或Runnable进行初始化,没有无参数的构造函数,Future和FutureTask都是只读的(FutureTask的设置方法是受保护的)。 该值将被设置为从内部计算的结果。

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

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

还要注意,承诺不一定是未来的一个子types,它不一定是同一个对象。 在Scala中,Future对象是由asynchronous计算或不同的 Promise对象创build的。 在C ++中情况是类似的:承诺对象被生产者和未来对象由消费者使用。 这种分离的好处是客户不能设定未来的价值。

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

我知道已经有了一个可以接受的答案,但是还是想加两分钱:

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

现在想想如何实现这个API方法: 实现者必须立即返回一个Future 。 一旦计算完成,她将负责完成这个未来(她将会知道,因为她正在执行调度逻辑;-))。 她将使用Promise / CompletableFuture来做到这一点:立即构造并返回CompletableFuture ,并在计算完成后调用complete(T result)

TLDR:Future和Promise是asynchronous操作的双方: 消费者/呼叫者生产者/实现者

我将举一个例子,说明什么是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 

妈妈的诺言是创build的,但是等待一些“完成”事件。

 CompletableFuture<Integer> promise... 

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

 promise.thenAccept... 

这时妈妈开始打开钱包,但是很慢…

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

 promise.complete(10); 

你注意到我写了一个执行者吗? 有趣的是,如果你使用默认的隐式执行器(commonPool)而父亲不在家,只有妈妈用她的“慢钱包”,那么她的承诺将只能完成,如果程序生活的时间比妈妈需要从钱中获得更多钱包。 我的意思是默认的执行者以“守护进程”的方式行事。 我还没有find这个事实的一个很好的描述…

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

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

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); }) 

这使asynchronous计算看起来像同步:

 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); } 

这很酷。 (不像asynchronous等待,asynchronous等待只是删除样板….然后(function(结果){….从它)。

实际上他们的抽象作为承诺构造函数是相当不错的

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

允许您提供两个callback,可用于成功完成Promise或出现错误。 所以只有构造Promise的代码才能完成它,接收已经构造的Promise对象的代码具有只读视图。

通过inheritance,如果parsing拒绝是受保护的方法,则可以实现上述目的。

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

Interesting Posts