lazy变量与双重检测锁(DCL)

本文深入探讨了Scala中Lazy变量的实现原理,采用双重检测锁(DCL)模式确保线程安全的延迟初始化。通过具体代码示例展示了如何使用状态标记变量进行初始化检查,并详细解释了编译后的JVM字节码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自:http://hongjiang.info/scala-lazy-and-dcl/

       scala里的lazy变量,背后的实现是个典型的双重检测锁(DCL)模式。比如:
class A{
    lazy val a=2
}
       对a的访问,先通过状态标记变量(做一次位与操作)判断是否已经初始化过。
       通过scalac -Xprint:jvm来看对a的访问:
lazy private[this] var a: Int = _;

// 通过标记变量的与1做位与操作,判断是否已初始化
lazy def a(): Int = if (A.this.bitmap$0.&(1).$asInstanceOf[Byte]().==(0))
  A.this.a$lzycompute()
else
  A.this.a;

       看看状态变量(需要用volatile修饰) 和延迟计算的逻辑:
// 定义一个可变的Byte类型的变量 bitmap$0
@volatile private[this] var bitmap$0: Byte = 0.$asInstanceOf[Byte]();

// 延迟计算的函数
private def a$lzycompute(): Int = {
  {
    // 线程安全
    A.this.synchronized({
      // 按位与操作,
      if (A.this.bitmap$0.&(1).$asInstanceOf[Byte]().==(0))
        {
          A.this.a = 2;
          // 改变 bitmap$0 的值,标记a已经赋值过了
          A.this.bitmap$0 = A.this.bitmap$0.|(1).$asInstanceOf[Byte]();
          ()
        };
      scala.runtime.BoxedUnit.UNIT
    });
    ()
  };
  A.this.a
};
      为什么用 Byte 变量而非用Boolean,是当有多个lazy成员时,可以用同一个状态变量,按”位”标记,而不必用多个Boolean变量来标识各个lazy成员的状态。
       比如有a,b,c 三个lazy成员,则 bitmap$0 第一位表示a,第二位表示b,第三位表示c,以此类推;判断时只要分别与1,2,4,8… 做位与操作就知道了。
       不过Byte类型最大只有8位,一个类中如果超过8个lazy成员,编译器就把 bitmap$0 状态变量改用Int类型了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值