异步计算
前述所有的并发计算都是先分解一个任务,然后等待,直到所有部分都已经完成。然而,等待并不总是合适的,本节将介绍如何实现无等待或异步的计算。
1. CompletableFuture<T>
类
当有一个 Future
对象时,需要调用 get
来获得值,这个方法会阻塞,直到值可用。可完成 Future
类 CompletableFuture
实现了 Future
接口,它提供了获得结果的另一种机制:注册一个回调,一旦结果可用,就会(在某个线程中)利用该结果调用这个回调。
通过这种方式,无须阻塞就可以在结果可用时对结果进行处理:
CompletableFuture<String> f = ...;
// Process the result string s
f.thenAccept(s -> ...);
要想异步运行任务并得到 CompletableFuture
,不要把它直接提交给 ExecutoreService
,而应当调用静态方法 CompletableFutre.supplyAsnc
。
CompletableFuture
可以采用两种方式完成:得到一个结果,或者有一个未捕获的异常。要处理这两种情况,可以使用 whenComplete
方法。
CompletableFuture
之所以被称为是可完成的,是因为你可以手动地设置一个完成值。在其他并发库中,这样的对象称为承诺(promise)。
与普通的 Future
不同,调用 cancle
方法时,CompletableFuture
的计算不会中断。取消只会把这个 Future
对象设置为以异常方式完成(有一个 CancellationException
异常)。
2. 组合CompletableFuture
CompletableFuture
类可以将异步任务组合为一个处理管道。
为 CompletableFuture<T>
对象增加一个动作:
方法 | 参数 | 描述 |
---|---|---|
thenApply | T -> U | 对结果应用一个函数 |
thenAccept | T -> void | 类似于 thenApply ,不过结果为 void |
thenCompose | T -> CompletableFutre<U> | 对结果调用函数并执行返回的 future |
handle | (T, Throwable) -> U | 处理结果或错误,生成一个新结果 |
whenComplete | (T, Throwable) -> void | 类似于 handle ,不过结果为 void |
exceptionally | Throwable -> T | 从错误计算一个结果 |
completeOnTimeout | T, long, TimeUnit | 如果超时,生成给定值作为结果 |
orTimeout | long, TimeUnit | 如果超时,生成一个 TimeoutException 异常 |
thenRun | Runnable | 执行 Runnable ,结果为 void |
组合多个 future
的方法:
方法 | 参数 | 描述 |
---|---|---|
thenCombine | CompletableFuture<U>, (T, U) -> V | 执行两个动作并用给定函数组合结果 |
thenAccepBoth | CompletableFuture<U>, (T, U) -> void | 与 thenCombine 类似,不过结果为 void |
runAfterBoth | CompletableFuture<?>, Runnable | 两个都完成后执行 runnable |
applyToEither | CompletableFuture<T>, (T) -> V | 得到其中一个的结果时,传入给定的函数 |
acceptEither | CompletableFuture<T>, T -> void | 与 applyToEither 类似,不过结果为 void |
runAfterEither | CompletableFuture<?>, Runnable | 其中一个完成后执行 runnable |
static allOf | CompletableFuture<?>... | 所有给定的 future 都完成后完成,结果为 void |
static anyOf | CompletableFuture<?>... | 任意给定的 future 完成后则完成,结果为 void |