3

동안 나는이의를 제외하고 (거의 동등한 종류의 생각하지만, 나는 JDK 8 CompletableFutureCompletableFuture와 ListenableFuture의 코 루틴 빌더간에 차이점은 무엇입니까? 코 틀린의 코 루틴의 소스를 검사

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 ** 
} 

Guava 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() } ** 
} 

통합 사이 (** 표시) 차이를 발견 물론 ListenableFuture을 직접 완료 할 수는 없지만이 문제가 왜 중요하지는 않습니다.) 이 차이 뒤에 특별한 이유가 있습니까?

답변

5

CompletableFuture.cancel은 개방형 (무시할 수있는) 방법이지만 용으로 설계된 이 아닙니다. 그 문서는 취소시 호출에 대한 보증을 제공하지 않으므로 CompletableFuture이 취소되었다는 것을 장래에 입증 할 수있는 유일한 방법은 수신기에 whenComplete 리스너를 설치하는 것입니다.

예를 들어, 향후 버전의 JDK가 내부적으로 cancel을 호출하지 않는 미래를 취소하는 또 다른 방법을 추가하는 것은 완전히 합법적입니다. 그러한 변경은 CompletableFuture 계약을 위반하지 않습니다.

AbstractFuture.interruptTask의 설명서와이를 비교하십시오. 이 메소드는 오버라이드 (override)를 위해서 (때문에) 명시 적으로 설계되어있어, 문서에 의해 오버라이드 (override)됩니다. 따라서 우리는 제거 리스너를 설치하기 위해 람다 생성을 피하는 ListenableFuture 빌더에 대해 약간 더 효율적인 구현을 제공 할 수 있습니다.