【问题标题】:Scala lazy values : performance penalty? Threadsafe? [duplicate]Scala 惰性值:性能损失?线程安全? [复制]
【发布时间】:2010-11-04 09:11:09
【问题描述】:

可能重复:
What's the (hidden) cost of lazy val? (Scala)

Scala 允许定义惰性值

lazy val maybeUnusedValue = someCostlyInitialization

其中someCostlyInitialization 仅在首次使用maybeUnusedValue 时进行评估。也就是说,它最多被评估一次,如果从不使用maybeUnusedValue,它也永远不会被评估。

这是线程安全的吗?这对性能有何影响? 如果这是线程安全的,它必须使用某种同步/以某种方式使用 Java volatile。不幸的是,Scala language specification 对此只字未提。

【问题讨论】:

标签: performance scala lazy-initialization


【解决方案1】:

使用双重检查锁定 http://code-o-matic.blogspot.com/2009/05/double-checked-locking-idiom-sweet-in.html 使其成为线程安全的显然这确实意味着访问惰性 val 比访问非惰性 val 慢。

【讨论】:

  • 所以,基本上,这意味着第一次访问惰性值比直接访问值慢得多(在奇怪的情况下甚至可能造成死锁),但随后的访问几乎不比非慢-惰性值。看来这不能掉以轻心,仅用于非常昂贵的初始化。
  • @hstoerr 在什么情况下会造成死锁?双重检查锁定似乎正确同步了这一点。
  • @Cristian Vrabie:我认为当时 Scala 只需要 Java 1.4,不是吗?而且 DCL 在 Java 1.4 中被破坏了。
  • @Alexey Romanov:啊,我忘了。我接触 Java 1.4 已经太久了。感谢您澄清这一点。
【解决方案2】:

更新:糟糕,正如 Vasil 指出的那样,问题是另一个线程的副本,而且碰巧,这个答案也是如此。

我上了这门课:

class Foo {
  lazy val test = "hi"
}

编译和反编译(使用jd-gui):

public class Foo
  implements ScalaObject
{
  private String test;
  public volatile int bitmap$0;

  public String test()
  {
    if (
      (this.bitmap$0 & 0x1) == 0);
    synchronized (this)
    {
      if (
        (this.bitmap$0 & 0x1) == 0) {
        this.test = "hi"; this.bitmap$0 |= 1; } return this.test;
    }
  }
}

如您所见,它使用带有 volatile 变量的双重检查范例。所以我认为它是安全的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 2015-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多