java - LazyReference 具有双重检查锁定和 null 处理

标签 java null volatile lazy-initialization double-checked-locking

我使用 LazyReference 类已有几年了(当然不是定期使用,但有时它非常有用)。类(class)可见here 。感谢 Robbie Vanbrabant(类(class)作者)和 Joshua Bloch 的著名“Effective Java 2nd edt”。 (原始代码)。

该类可以正常工作(在 Java 5+ 中),但存在一个潜在的小问题。如果 instanceProvider 返回 null (当然,它不能根据 Guice Provider.get() 契约,但是......),然后在每次执行 时>LazyReference.get() 方法将保留 LOCK,并且会一遍又一遍地调用 instanceProvider.get。对于那些违反契约(Contract)的人来说,这看起来是一个很好的惩罚(嘿嘿),但如果真的需要延迟初始化一个可以设置 null 值的字段怎么办?

我稍微修改了 LazyReference:

public class LazyReference<T> {

  private final Object LOCK = new Object();

  private volatile T instance;

  private volatile boolean isNull;

  private final Provider<T> instanceProvider;

  private LazyReference(Provider<T> instanceProvider) {
    this.instanceProvider = instanceProvider;
  }

  public T get() {
    T result = instance;
    if (result == null && !isNull) {
      synchronized (LOCK) {
        result = instance;
        if (result == null && !isNull) {
          instance = result = instanceProvider.get();
          isNull = (result == null);
        }
      }
    }
    return result;
  }
}

恕我直言,它应该工作得很好(如果您有其他意见,请发表您的评论和批评)。但我想知道如果我从 isNull boolean 值中删除 volatile 修饰符(当然将其留给实例)会发生什么?它还能正常工作吗?

最佳答案

上面的代码有一个竞争条件:在设置 isNull 之前,instance 可能会从 instanceProvider.get() 的结果设置为“真正的”null。

您确定放弃这些复杂的废话并正确同步对您来说不会更容易吗?我敢打赌您将无法测量性能的任何差异,并且会更容易验证您的代码是否正确。

关于java - LazyReference 具有双重检查锁定和 null 处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6444823/

相关文章:

java - Java中图像计算方程

sql - 将数据从 SQL 导出到 XML - NULL 值

null - 如何删除空值?

button - dart MouseEvent toElement null

java - 在 Java 中使子类中的变量可变

java - 为什么 Selenium 在 Google 主页上识别一个按钮而不是两个按钮

java - 是否可以在运行时从 Java 设置环境变量?

java - 如何访问 JPA 查询中的多个字段?

c - 为什么在一个序列点内最多只能有一个具有 volatile 限定类型的读取访问?

c - 我应该在这个库中使用 volatile 吗(以及在哪里)?