CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
105
(到目前为止,我对答案并不完全满意,所以这是我的尝试......)
我认为Kevin Wright的评论("You can make a Promise and it's up to you to keep it. When someone else makes you a promise you must wait to see if they honour it in the Future")很好地总结了它,但是一些解释可能很有用 .
7 回答
根据this discussion,
Promise
最终被称为CompletableFuture
以包含在Java 8中,its javadoc解释说:列表中还给出了一个示例:
请注意,最终的API略有不同,但允许类似的异步执行:
(到目前为止,我对答案并不完全满意,所以这是我的尝试......)
我认为Kevin Wright的评论("You can make a Promise and it's up to you to keep it. When someone else makes you a promise you must wait to see if they honour it in the Future")很好地总结了它,但是一些解释可能很有用 .
Futures and promises是非常相似的概念,不同之处在于,future是一个只读容器,用于尚未存在的结果,而promise可以写入(通常只有一次) . Java 8 CompletableFuture和Guava SettableFuture可以被认为是promises,因为它们的值可以设置("completed"),但它们也实现了Future接口,因此客户端没有区别 .
未来的结果将由"someone else"设置 - 由异步计算的结果 . 注意FutureTask - 一个经典的未来 - 必须用Callable或Runnable初始化,没有无参数构造函数,Future和FutureTask都是从外部读取的(FutureTask的set方法受到保护) . 该值将从内部设置为计算结果 .
另一方面,承诺的结果可以随时由“你”(或实际上由任何人)设置,因为它具有公共setter方法 . CompletableFuture和SettableFuture都可以在没有任何任务的情况下创建,并且可以随时设置它们的值 . 您向客户端代码发送承诺,并在以后按照您的意愿完成 .
请注意,CompletableFuture不是“纯粹”的承诺,它可以像FutureTask一样使用任务进行初始化,其最有用的功能是处理步骤的无关链接 .
另请注意,promise不必是future的子类型,也不必是同一个对象 . 在Scala中,Future对象由异步计算或不同的Promise对象创建 . 在C中情况类似: 生产环境 者使用promise对象,消费者使用未来对象 . 这种分离的好处是客户无法设定未来的 Value .
Spring和EJB 3.1都有一个AsyncResult类,类似于Scala / C承诺 . AsyncResult确实实现了Future,但这不是真正的未来:Spring / EJB中的异步方法通过一些背景魔法返回一个不同的只读Future对象,客户端可以使用第二个"real" future来访问结果 .
我知道已经有一个已接受的答案,但我想加上我的两分钱:
TLDR:Future和Promise是异步操作的两个方面: consumer/caller 与 producer/implementor .
作为异步API方法的 caller ,您将获得 Future 作为计算结果的句柄 . 你可以,例如在其上调用
get()
等待计算完成并检索结果 .现在想想这个API方法是如何实现的: implementor 必须立即返回
Future
. 一旦计算完成,她就有责任完成这个未来(她知道因为她正在实施调度逻辑;-)) . 她将使用 Promise / CompletableFuture 来做到这一点:立即构造并返回CompletableFuture
,并在计算完成后调用complete(T result)
.我将举例说明什么是Promise以及如何在任何时候设置其值,与Future相反,该值只能读取 .
假设你有一个妈妈,你问她要钱 .
现在,你欺骗你的妈妈为你创造一个最终捐赠的承诺,她给你这个承诺对象,但她并没有真正轻率地实现它:
你很高兴,你要感谢你的妈妈:
但是你的父亲会干涉并且通常会中止妈妈的计划并完成承诺(设定其 Value !)的贡献要小得多,正如父亲那样,非常坚决,而妈妈正在慢慢打开她的钱包(注意Thread.sleep(...)):
输出是:
妈妈的承诺已经创建,但等待一些“完成”事件 .
你创建了这样的活动,接受了她的承诺,并宣布你的计划,感谢你的妈妈:
这时妈妈开始打开她的钱包......但很慢......
和父亲干涉得更快,完成了承诺,而不是你的妈妈:
您是否注意到我明确写过的执行人?有趣的是,如果你使用默认的隐式 Actuator (commonPool)而且父亲不在家,只有妈妈带着她的“慢钱包”,那么她的承诺只会完成,如果该计划比妈妈需要更多时间从钱包里拿钱 . 我的意思是默认执行程序以“守护进程”的方式运行 . 我还没有找到这个事实的好描述......
不确定这是否可以作为答案但是当我看到其他人对某人所说的内容时,您可能看起来需要对这两个概念进行两个单独的抽象,以便其中一个(
Future
)只是另一个的只读视图(Promise
)......但实际上这不是必需的 .例如,看看如何在javascript中定义promises:
https://promisesaplus.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
重点是使用
then
方法的可组合性,如:这使异步计算看起来像同步:
这很酷 . (不像async-await那样酷,但async-await只是删除样板....然后(函数(结果){....从它) .
实际上,他们的抽象作为promise构造函数非常好
允许您提供两个回调,可用于成功完成
Promise
或出错 . 因此,只有构造Promise
的代码才能完成它,并且接收已构造的Promise
对象的代码具有只读视图 .通过继承,如果解析和拒绝是受保护的方法,则可以实现上述目的 .
Future接口中没有set方法,只有get方法,因此它是只读的 . 关于CompletableFuture,这篇文章可能会有所帮助 . completablefuture
对于客户端代码,Promise用于在结果可用时观察或附加回调,而Future是等待结果然后继续 . 从理论上讲,任何可能与期货有关的事情都可以通过承诺完成,但由于风格的差异,所产生的不同语言承诺的API使链接更容易 .