为什么当引发异常时,Scala中的原子块会运行两次?

时间:2018-06-22 13:54:30

标签: scala exception atomic stm

代码:

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

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

1 个答案:

答案 0 :(得分:4)

ScalaSTM文档中this page的底部是这样的:

  

为使嵌套非常便宜,ScalaSTM尝试将所有   将级别嵌套在一起,成为一个顶级事务。如果   内部交易引发异常,那么还不够   信息以执行部分​​回滚,因此ScalaSTM重新启动   以完全嵌套的模式进行整个交易。这个   优化称为包容。

那么会发生什么:

  1. 尝试将整个事情作为“扁平化”交易
  2. last设置为"outer"
  3. last设置为"inner"
  4. "inner"已打印
  5. 内部原子块引发异常,外部原子块不引发
  6. ScalaSTM不知道如何仅回退内部事务,因为它已“展平”,因此回滚了整个事务(last现在又回到了"none")并重试了“非-flattened”
  7. last设置为"outer"
  8. last设置为"inner"
  9. "inner已打印
  10. 内部原子块引发异常,该异常被外部块捕获
  11. 这一次由于未展平,因此只能回滚内部块,并且last设置回"outer"
相关问题