给出以下代码:
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)
未来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会正确处理它,但这是一个非常糟糕的解决方案。
这是一个已知问题吗?预期的行为?我有什么方法可以从我的期货中获得理智的行为?
答案 0 :(得分:10)
来自Future的来源。
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
如您所见,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
}
由于java.lang.InternalError是VirtualMachineError
的子类,运行任务的线程只是被异常杀死,并且承诺永远不会完成。
在执行失败的异步计算的线程中重新抛出致命异常(由NonFatal确定)。这通知管理问题的执行线程的代码,并允许它在必要时快速失败。有关语义的更精确描述,请参阅NonFatal。
因此我认为这是预期的行为。