在 GitHub 上编辑此页面

延迟值初始化

Scala 3 实现了 SIP-20 提案的第 6 版,该提案改进了延迟值初始化。

动机

新提出的惰性 val 初始化机制旨在消除在惰性 val 初始化块执行期间获取资源,从而降低死锁的可能性。新惰性 val 初始化方案消除的具体死锁场景总结在 SIP-20 文档中。

实现

给定一个形式为

class Foo {
  lazy val bar = <RHS>
}

的惰性字段,Scala 3 编译器将生成等效于

class Foo {
  import scala.runtime.LazyVals
  var value_0: Int = _
  var bitmap: Long = 0L
  val bitmap_offset: Long = LazyVals.getOffset(classOf[LazyCell], "bitmap")

  def bar(): Int = {
    while (true) {
      val flag = LazyVals.get(this, bitmap_offset)
      val state = LazyVals.STATE(flag, <field-id>)

      if (state == <state-3>) {
        return value_0
      } else if (state == <state-0>) {
        if (LazyVals.CAS(this, bitmap_offset, flag, <state-1>, <field-id>)) {
          try {
            val result = <RHS>
            value_0 = result
            LazyVals.setFlag(this, bitmap_offset, <state-3>, <field-id>)
            return result
          }
          catch {
            case ex =>
              LazyVals.setFlag(this, bitmap_offset, <state-0>, <field-id>)
              throw ex
          }
        }
      } else /* if (state == <state-1> || state == <state-2>) */ {
        LazyVals.wait4Notification(this, bitmap_offset, flag, <field-id>)
      }
    }
  }
}

的代码。惰性 val <state-i> 的状态用 4 个值表示:0、1、2 和 3。状态 0 表示未初始化的惰性 val。状态 1 表示当前正在由某个线程初始化的惰性 val。状态 2 表示存在对惰性 val 的并发读取器。状态 3 表示已初始化的惰性 val。<field-id> 是惰性 val 的 id。此 id 随着类中定义的易失性惰性 val 的数量而增长。

关于递归惰性 val 的说明

理想情况下,递归惰性 val 应该被标记为错误。当前递归惰性 val 的行为是未定义的(初始化可能导致死锁)。

参考