¿Por qué hay una diferencia entre los constructores de coroutine para CompletableFuture y ListenableFuture?

Mientras examinaba la fuente de corotines de Kotlin, noté una diferencia (marcada con ** ) entre 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 ** } 

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

integraciones, aunque pienso que los types son casi equivalentes (excepto por supuesto que ListenableFuture no se puede completar directamente, pero no veo por qué esto importa aquí). ¿Hay alguna razón específica detrás de esta diferencia?

CompletableFuture.cancel es un método abierto (anulable), pero no está diseñado para sobrescribir . Su documentation no proporciona ninguna garantía para su invocación en caso de cancelación, por lo que la única forma de comprobar el futuro (con intención de juego) para saber que CompletableFuture fue cancelado es instalando el oyente whenComplete en él.

Por ejemplo, es perfectamente legal que una versión futura de JDK agregue otro método para cancelar un futuro que no invoque internamente la cancel . Tal cambio no violaría ninguna parte del contrato de CompletableFuture .

Compare esto con la documentation en AbstractFuture.interruptTask . Este método está explícitamente diseñado para sobrescribir y su documentation garantiza las condiciones bajo las cuales se invoca. Por lo tanto, podemos proporcionar una implementación un poco más eficiente para el constructor ListenableFuture que evita la creación de lambda para instalar un oyente de cancelación en él.

  • ¿Cómo se ejecuta el método de suspensión a través de la reflexión?
  • Spring 5 and Kotlin 1.1 Coroutines: Type rx.Scheduler no presente
  • Kotlin Coroutines con time de espera
  • Corotines de Kotlin: ajuste el uso sincrónico de cassandra frente a la traducción del uso asynchronous
  • reference no resuelta: lanzamiento
  • Kotlin Process Collection En Paralelo?
  • Kotlin coroutines usa produce y mockito para burlarse del trabajo de producción
  • "+" En Kotlin Coroutines?
  • Oyente dentro del productor
  • Kotlin: ArrayIndexOutOfBoundsException durante la conversión de DispatchTask a cadena
  • Limpiar el uso de Coroutines en Kotlin con el soporte de testing unitaria