为什么 Scala 中的原子块在抛出异常时运行两次?



Code:

object Blub {
import scala.concurrent.stm._
val last = Ref("none")
def bla() = atomic { implicit txn =>
last() = "outer"
try {
atomic { implicit txn =>
last() = "inner"
println(last())
throw new RuntimeException
}
} catch {
case _: RuntimeException =>
}
}
def main(args: Array[String]): Unit = {
bla()
println("Result: "+last.single())
}
}

输出:

inner  
inner  
Result: outer

谁能解释为什么内部原子块运行两次?我知道由于异常,它会回滚,因此最终结果。但我不明白为什么它会第二次运行代码。

ScalaSTM 文档的本页底部是这样说的:

为了使嵌套变得非常便宜,ScalaSTM试图将所有嵌套扁平化。 将级别嵌套到单个顶级事务中。如果 内部事务抛出异常,则没有足够的异常 信息来执行部分回滚,因此 ScalaSTM 重新启动 整个事务处于执行精确嵌套的模式下。这 优化称为包容。

所以发生的事情是:

  1. 整个事情被尝试为"扁平化"事务
  2. last设置为"outer"
  3. last设置为"inner"
  4. 打印"inner"
  5. 内部原子块引发异常,外部块不会
  6. ScalaSTM 不知道如何回滚内部事务,因为它运行"扁平化",所以它会回滚整个事情(last现在回到"none"(并重试它"非扁平化">
  7. last设置为"outer"
  8. last设置为"inner"
  9. 打印"inner
  10. 内部原子块引发异常,该异常被外部块捕获
  11. 这次由于它是非扁平的,它只能回滚内部块,last被设置回"outer"

最新更新