延迟值初始化
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 的行为是未定义的(初始化可能导致死锁)。
参考
本文内容