为什么CompletableFuture和ListenableFuture的协程构建器之间存在差异?

Ale*_*nov 4 coroutine java.util.concurrent guava kotlin kotlin-coroutines

在检查Kotlin协同程序的来源时,我注意到JDK 8 CompletableFuture**之间存在差异(标记为)

public fun <T> future(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): CompletableFuture<T> {
    require(!start.isLazy) { "$start start is not supported" }
    val newContext = newCoroutineContext(context)
    val job = Job(newContext[Job])
    val future = CompletableFutureCoroutine<T>(newContext + job)
    job.cancelFutureOnCompletion(future)
    ** future.whenComplete { _, exception -> job.cancel(exception) } **
    start(block, receiver=future, completion=future) // use the specified start strategy
    return future
}


private class CompletableFutureCoroutine<T>(
    override val context: CoroutineContext
) : CompletableFuture<T>(), Continuation<T>, CoroutineScope {
    override val coroutineContext: CoroutineContext get() = context
    override val isActive: Boolean get() = context[Job]!!.isActive
    override fun resume(value: T) { complete(value) }
    override fun resumeWithException(exception: Throwable) { completeExceptionally(exception) }
    ** doesn't override cancel which corresponds to interrupt task **
}
Run Code Online (Sandbox Code Playgroud)

番石榴ListenableFuture

public fun <T> future(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): ListenableFuture<T> {
    require(!start.isLazy) { "$start start is not supported" }
    val newContext = newCoroutineContext(context)
    val job = Job(newContext[Job])
    val future = ListenableFutureCoroutine<T>(newContext + job)
    job.cancelFutureOnCompletion(future)
    start(block, receiver=future, completion=future) // use the specified start strategy
    return future
}

private class ListenableFutureCoroutine<T>(
    override val context: CoroutineContext
) : AbstractFuture<T>(), Continuation<T>, CoroutineScope {
    override val coroutineContext: CoroutineContext get() = context
    override val isActive: Boolean get() = context[Job]!!.isActive
    override fun resume(value: T) { set(value) }
    override fun resumeWithException(exception: Throwable) { setException(exception) }
    ** override fun interruptTask() { context[Job]!!.cancel() } **
}
Run Code Online (Sandbox Code Playgroud)

集成,虽然我认为类型几乎相同(当然除了ListenableFuture不能直接完成,但我不明白为什么这里重要).这种差异背后有一个具体原因吗?

Rom*_*rov 8

所述CompletableFuture.cancel是一个开放的(可重写)的方法,但它不是设计用于超驰.它的文档没有为其取消调用提供任何保证,因此唯一能够在未来证明(双关语)学习CompletableFuture取消的方法是whenComplete在其上安装监听器.

例如,对于未来版本的JDK来说,添加另一种取消未在内部调用的未来的方法是完全合法的cancel.这样的改变不会违反任何CompletableFuture合同.

将其与AbstractFuture.interruptTask上的文档进行比较.此方法明确设计用于覆盖,其文档保证调用它的条件.因此,我们可以为ListenableFuture构建器提供稍微更有效的实现,避免创建lambda以在其上安装取消侦听器.