You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method
待处理的阶段首先创建, 每个阶段都是转换一个字符串为大写。因为本例中这些阶段都是同步地执行(thenApply), 从anyOf中创建的CompletableFuture会立即完成,这样所有的阶段都已完成,我们使用whenComplete(BiConsumer<? super Object, ? super Throwable> action)处理完成的结果。
[译]20个使用 Java CompletableFuture的例子
https://ift.tt/2Q5dQzq
在Java中异步编程,不一定非要使用rxJava, Java本身的库中的CompletableFuture可以很好的应对大部分的场景。
原文: 20 Examples of Using Java’s CompletableFuture, 作者 Mahmoud Anouti。
这篇文章介绍 Java 8 的 CompletionStage API和它的标准库的实现 CompletableFuture。API通过例子的方式演示了它的行为,每个例子演示一到两个行为。
既然
CompletableFuture
类实现了CompletionStage
接口,首先我们需要理解这个接口的契约。它代表了一个特定的计算的阶段,可以同步或者异步的被完成。你可以把它看成一个计算流水线上的一个单元,最终会产生一个最终结果,这意味着几个CompletionStage
可以串联起来,一个完成的阶段可以触发下一阶段的执行,接着触发下一次,接着……除了实现
CompletionStage
接口,CompletableFuture
也实现了future
接口, 代表一个未完成的异步事件。CompletableFuture
提供了方法,能够显式地完成这个future,所以它叫CompletableFuture
。1、 创建一个完成的CompletableFuture
最简单的例子就是使用一个预定义的结果创建一个完成的CompletableFuture,通常我们会在计算的开始阶段使用它。
getNow(null)
方法在future完成的情况下会返回结果,就比如上面这个例子,否则返回null (传入的参数)。2、运行一个简单的异步阶段
这个例子创建一个一个异步执行的阶段:
通过这个例子可以学到两件事情:
CompletableFuture的方法如果以
Async
结尾,它会异步的执行(没有指定executor的情况下), 异步执行通过ForkJoinPool实现, 它使用守护线程去执行任务。注意这是CompletableFuture的特性, 其它CompletionStage可以override这个默认的行为。3、在前一个阶段上应用函数
下面这个例子使用前面 #1 的完成的CompletableFuture, #1返回结果为字符串
message
,然后应用一个函数把它变成大写字母。注意
thenApply
方法名称代表的行为。then
意味着这个阶段的动作发生当前的阶段正常完成之后。本例中,当前节点完成,返回字符串message
。Apply
意味着返回的阶段将会对结果前一阶段的结果应用一个函数。函数的执行会被阻塞,这意味着
getNow()
只有打斜操作被完成后才返回。4、在前一个阶段上异步应用函数
通过调用异步方法(方法后边加Async后缀),串联起来的CompletableFuture可以异步地执行(使用ForkJoinPool.commonPool())。
5、使用定制的Executor在前一个阶段上异步应用函数
异步方法一个非常有用的特性就是能够提供一个Executor来异步地执行CompletableFuture。这个例子演示了如何使用一个固定大小的线程池来应用大写函数。
6、消费前一阶段的结果
如果下一阶段接收了当前阶段的结果,但是在计算的时候不需要返回值(它的返回类型是void), 那么它可以不应用一个函数,而是一个消费者, 调用方法也变成了
thenAccept
:本例中消费者同步地执行,所以我们不需要在CompletableFuture调用
join
方法。7、异步地消费迁移阶段的结果
同样,可以使用
thenAcceptAsync
方法, 串联的CompletableFuture可以异步地执行。8、完成计算异常
现在我们来看一下异步操作如何显式地返回异常,用来指示计算失败。我们简化这个例子,操作处理一个字符串,把它转换成答谢,我们模拟延迟一秒。
我们使用
thenApplyAsync(Function, Executor)
方法,第一个参数传入大写函数, executor是一个delayed executor,在执行前会延迟一秒。让我们看一下细节。
首先我们创建了一个CompletableFuture, 完成后返回一个字符串
message
,接着我们调用thenApplyAsync
方法,它返回一个CompletableFuture。这个方法在第一个函数完成后,异步地应用转大写字母函数。这个例子还演示了如何通过
delayedExecutor(timeout, timeUnit)
延迟执行一个异步任务。我们创建了一个分离的
handler
阶段: exceptionHandler, 它处理异常异常,在异常情况下返回message upon cancel
。下一步我们显式地用异常完成第二个阶段。 在阶段上调用
join
方法,它会执行大写转换,然后抛出CompletionException(正常的join会等待1秒,然后得到大写的字符串。不过我们的例子还没等它执行就完成了异常), 然后它触发了handler阶段。9、取消计算
和完成异常类似,我们可以调用
cancel(boolean mayInterruptIfRunning)
取消计算。对于CompletableFuture类,布尔参数并没有被使用,这是因为它并没有使用中断去取消操作,相反,cancel
等价于completeExceptionally(new CancellationException())
。10、在两个完成的阶段其中之一上应用函数
下面的例子创建了
CompletableFuture
,applyToEither
处理两个阶段, 在其中之一上应用函数(包保证哪一个被执行)。 本例中的两个阶段一个是应用大写转换在原始的字符串上, 另一个阶段是应用小些转换。11、在两个完成的阶段其中之一上调用消费函数
和前一个例子很类似了,只不过我们调用的是消费者函数 (Function变成Consumer):
12、在两个阶段都执行完后运行一个
Runnable
这个例子演示了依赖的CompletableFuture如果等待两个阶段完成后执行了一个Runnable。 注意下面所有的阶段都是同步执行的,第一个阶段执行大写转换,第二个阶段执行小写转换。
13、 使用BiConsumer处理两个阶段的结果
上面的例子还可以通过BiConsumer来实现:
14、使用BiFunction处理两个阶段的结果
如果CompletableFuture依赖两个前面阶段的结果, 它复合两个阶段的结果再返回一个结果,我们就可以使用
thenCombine()
函数。整个流水线是同步的,所以getNow()
会得到最终的结果,它把大写和小写字符串连接起来。15、异步使用BiFunction处理两个阶段的结果
类似上面的例子,但是有一点不同: 依赖的前两个阶段异步地执行,所以
thenCombine()
也异步地执行,即时它没有Async
后缀。Javadoc中有注释:
所以我们需要
join
方法等待结果的完成。16、组合 CompletableFuture
我们可以使用
thenCompose()
完成上面两个例子。这个方法等待第一个阶段的完成(大写转换), 它的结果传给一个指定的返回CompletableFuture函数,它的结果就是返回的CompletableFuture的结果。有点拗口,但是我们看例子来理解。函数需要一个大写字符串做参数,然后返回一个CompletableFuture, 这个CompletableFuture会转换字符串变成小写然后连接在大写字符串的后面。
17、当几个阶段中的一个完成,创建一个完成的阶段
下面的例子演示了当任意一个CompletableFuture完成后, 创建一个完成的CompletableFuture.
待处理的阶段首先创建, 每个阶段都是转换一个字符串为大写。因为本例中这些阶段都是同步地执行(thenApply), 从
anyOf
中创建的CompletableFuture会立即完成,这样所有的阶段都已完成,我们使用whenComplete(BiConsumer<? super Object, ? super Throwable> action)
处理完成的结果。18、当所有的阶段都完成后创建一个阶段
上一个例子是当任意一个阶段完成后接着处理,接下来的两个例子演示当所有的阶段完成后才继续处理, 同步地方式和异步地方式两种。
19、当所有的阶段都完成后异步地创建一个阶段
使用
thenApplyAsync()
替换那些单个的CompletableFutures的方法,allOf()
会在通用池中的线程中异步地执行。所以我们需要调用join
方法等待它完成。20、真实的例子
Now that the functionality of CompletionStage and specifically CompletableFuture is explored, the below example applies them in a practical scenario:
现在你已经了解了CompletionStage 和 CompletableFuture 的一些函数的功能,下面的例子是一个实践场景:
cars
方法获得Car的列表,它返回CompletionStage场景。cars
消费一个远程的REST API。rating(manufacturerId)
返回一个CompletionStage, 它会异步地获取汽车的评分(可能又是一个REST API调用)allOf
得到最终的阶段, 它在前面阶段所有阶段完成后才完成。whenComplete()
,我们打印出每个汽车和它的评分。因为每个汽车的实例都是独立的,得到每个汽车的评分都可以异步地执行,这会提高系统的性能(延迟),而且,等待所有的汽车评分被处理使用的是
allOf
方法,而不是手工的线程等待(Thread#join() 或 a CountDownLatch)。这些例子可以帮助你更好的理解相关的API,你可以在github上得到所有的例子的代码。
其它参考文档
Comp
via 鸟窝 https://colobu.com/
March 12, 2018 at 05:14PM
The text was updated successfully, but these errors were encountered: