单一和双重检查延迟初始化

Single- and double-check lazy initialization

我无法理解 'Effective Java' 中第 71 项中关于延迟初始化实例字段的双重检查习惯用法和单次检查习惯用法的一段代码:

仔细检查成语

private volatile FieldType field;
FieldType getField() {
  FieldType result = field;
  if (result == null) {
    synchronized(this) {
      result == field;
      if (result == null)
        field = result = computeFieldValue();
    }
  }
  return result;
}

单查成语

private volatile FieldType field;
FieldType getField() {
  FieldType result = field;
  if (result == null) {
    field = result = computeFieldValue();
  }
  return result;
}

据我所知,我们在第一种情况下使用锁定,以便 compute FieldValue() 自动执行。但是为什么我们在第二种情况下省略它呢?因为现在一些外来线程可能会破坏一些参与计算的值。我错过了什么?

双重检查锁定的要点是确保computeFieldValue只被调用一次,并且字段只被写入一次。

在某些情况下可以多次调用此方法,使双重检查锁定变得过大。这些是需要满足的一些条件:

  • computeFieldValue 应该是 纯函数,始终返回相同的值;
  • 它被多次调用的风险程度是可以接受的(发生这种情况的可能性乘以其性能影响)。