例外导致Future永远不会完成

phe*_*ver 5 scala

给出以下代码:

import scala.concurrent.ExecutionContext
import java.util.concurrent.Executors

val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))

val f = Future[Unit](throw new java.lang.InternalError())(ec)
Run Code Online (Sandbox Code Playgroud)

未来f永远不会完成.f.value永远None.

scala-2.10中有一个已知错误已被修复:

http://mandubian.com/2013/02/22/scala-future-fatal-exception

https://issues.scala-lang.org/browse/SI-7029

我在scala-2.11上.

错误报告中的示例使用NotImplementedErorr,它由Future正确处理,它将完成.但是,如果我在上面的示例中使用InternalError,那么Future永远不会完成.无论我使用ExecutionContext.global,Executors.newSingleThreadExecutor还是Executors.newFixedThreadPool,都是如此.

我可以在未来的身体中抓住Throwable并重新抛出它,并且我知道Future会正确处理它,但这是一个可怕的解决方案.

这是一个已知的问题?预期的行为?我有什么选择可以从我的期货中获得理智的行为?

ymo*_*nad 10

来自未来的来源.

override def run() = {
  promise complete {
    try Success(body) catch { case NonFatal(e) => Failure(e) }
  }
}
Run Code Online (Sandbox Code Playgroud)

如你所见,Future只是捕捉NonFatal异常.

以下是NonFatal匹配的内容.

def apply(t: Throwable): Boolean = t match {
  // VirtualMachineError includes OutOfMemoryError and other fatal errors
  case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
  case _ => true
Run Code Online (Sandbox Code Playgroud)

}

由于java.lang.InternalError是子类 VirtualMachineError,因此运行任务的线程只是被异常杀死,并且永远不会完成promise.

从概述未来例外情况

在执行失败的异步计算的线程中重新抛出致命异常(由NonFatal确定).这通知管理问题的执行线程的代码,并允许它在必要时快速失败.有关语义的更精确描述,请参阅NonFatal.

因此我认为这是预期的行为.

  • 是的,在线程中重新抛出异常显然是有意的行为,但这似乎是一种疏忽,这会导致 Future 永远不会完成。用户需要确保在 Future 上等待的任何内容都通过其他机制获得失败通知。 (2认同)