Answers:
根据讨论,Promise
终于被要求CompletableFuture
包含在Java 8中,其javadoc解释了:
可以明确完成(设置其值和状态)并可以用作CompletionStage的Future,它支持在完成时触发的相关功能和操作。
清单上还提供了一个示例:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
请注意,最终的API稍有不同,但允许类似的异步执行:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(到目前为止,我对答案并不完全满意,所以这是我的尝试...)
我认为,凯文·赖特(Kevin Wright)的评论(“您可以作出承诺,而您应遵守承诺。当其他人向您许下诺言时,您必须拭目以待,看看他们是否会在未来兑现它”),但它的总结很不错,但是有些解释会很有用。
期货和承诺是非常相似的概念,不同之处在于,期货是一个尚不存在的结果的只读容器,而承诺可以被写入(通常只能写入一次)。可以将Java 8 CompletableFuture和Guava SettableFuture视为承诺,因为可以设置它们的值(“ completed”),但是它们也实现Future接口,因此客户端没有区别。
未来的结果将由“其他人”设置-由异步计算的结果确定。请注意,必须使用Callable或Runnable初始化FutureTask(经典的Future),没有无参数构造函数,并且Future和FutureTask都是从外部只读的(FutureTask的set方法受保护)。该值将从内部设置为计算结果。
另一方面,承诺的结果可以由“您”(或实际上任何人)随时设置,因为它具有公共设置方法。可以创建CompletableFuture和SettableFuture,而无需执行任何任务,并且可以随时设置它们的值。您向客户代码发送一个承诺,并在以后根据需要履行。
请注意,CompletableFuture并非“纯粹的”承诺,可以使用诸如FutureTask之类的任务对其进行初始化,并且其最有用的功能是与处理步骤无关的链接。
还要注意,promise不必是Future的子类型,也不必是同一对象。在Scala中,通过异步计算或其他 Promise对象创建Future 对象。在C ++中,情况类似:生产者使用Promise对象,消费者使用Future对象。这种分离的优点是客户无法设定未来的价值。
两个弹簧和EJB 3.1具有AsyncResult类,它是类似于斯卡拉/ C ++承诺。AsyncResult确实实现了Future,但这不是真正的未来:Spring / EJB中的异步方法通过一些背景魔术返回一个不同的只读Future对象,并且客户端可以使用第二个“真实”的Future来访问结果。
我知道已经有了一个可以接受的答案,但还是要加上我的两分钱:
TLDR:Future和Promise是异步操作的两个方面:消费者/调用者与生产者/实现者。
作为异步API方法的调用者,您将获得a Future
作为计算结果的句柄。您可以例如调用get()
它以等待计算完成并检索结果。
现在考虑一下该API方法的实际实现方式:实现者必须Future
立即返回一个。他们有责任在计算完成后立即完成将来的任务(由于执行分派逻辑,它们会知道这一点;-)。他们将使用Promise
/ CompletableFuture
来做到这一点:构造并CompletableFuture
立即返回立即数,并complete(T result)
在计算完成后立即调用。
我将举一个什么是Promise以及如何在任何时候设置其值的示例,与Future相反,后者仅是可读的。
假设您有一个妈妈,您要她要钱。
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
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);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
输出是:
Thank you mom for $10
妈妈的诺言已创建,但等待一些“完成”事件。
CompletableFuture<Integer> promise...
您创建了这样的活动,接受了她的诺言并宣布了要感谢您妈妈的计划:
promise.thenAccept...
这时妈妈开始打开钱包...但是非常慢...
父亲比您妈妈更快地干预并完成了诺言:
promise.complete(10);
您是否注意到我明确写过的遗嘱执行人?
有趣的是,如果您使用默认的隐式执行器(commonPool)且父亲不在家里,而只有妈妈带着“慢钱包”,则她的诺言只会兑现,前提是该程序的寿命超过了妈妈从中获得钱的需要钱包。
默认执行程序的行为类似于“守护程序”,并且不等待所有诺言得到兑现。我还没有找到关于这个事实的好描述...
不知道这是否可以作为答案,但是正如我看到别人对某人说的那样,这两个概念似乎都需要两个单独的抽象,因此其中一个(Future
)只是另一个概念的只读视图()。Promise
)...但实际上并不需要。
例如看一下如何在javascript中定义promise:
https://developer.mozilla.org/zh-CN/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只是删除了样板.... then(function(result){....)。)
实际上,它们的抽象作为promise构造器非常好
new Promise( function(resolve, reject) { /* do it */ } );
允许您提供两个回调,可用于Promise
成功完成或发生错误。这样,只有构造的代码Promise
才能完成它,而接收已经构造的Promise
对象的代码具有只读视图。
如果解决方法和拒绝方法是受保护的方法,则通过继承可以实现上述目的。
CompletableFuture
可能与a有一些相似之处,Promise
但仍然不是aPromise
,因为它打算使用的方式不同:a Promise
的结果是通过调用消耗的then(function)
,并且函数在生产者调用之后立即在生产者的上下文中执行resolve
。甲Future
的结果是通过调用消耗get
这会导致消费者线程等待,直到生产者线程已产生的值,则在消费处理它。 Future
本质上是多线程的,但是...
Promise
线程(实际上,这是它们最初设计的确切环境:javascript应用程序通常只有一个线程,因此您无法在其中实现Future
)。 Promise
因此,它比更加轻巧和高效Future
,但是Future
在更复杂的情况下以及需要使用Promise
s 难以安排的线程之间的协作的情况下会很有用。总结一下:Promise
是推模型,而Future
拉模型(参见Iterable vs Observable)
XMLHttpRequest
)。我不相信效率要求,您碰巧有一些数字吗?+++那是一个很好的解释。
get
一个未解决的问题Future
将必然涉及2个线程上下文切换,至少在几年前可能需要大约50 us。
Promise
并且要保留它。当别人向您许下诺言时,您必须等待,看看他们是否兑现了诺言Future