0

我已经使用LazyReference类几年了(当然不是定期使用,但有时它非常有用)。课程可以在这里看到。归功于 Robbie Vanbrabant(课程作者)和 Joshua Bloch 以及他著名的“Effective Java 2nd edt”。(原始代码)。

该类可以正常工作(在 Java 5+ 中),但存在一个小问题。如果instanceProvider返回null(当然它不能根据 GuiceProvider.get()合同,但是......)然后在每次执行LazyReference.get()方法时,LOCK 将被持有并被instanceProvider.get一遍又一遍地调用。对于那些违反合同的人来说,这似乎是一种很好的惩罚(he-he),但如果真的需要懒惰地初始化一个可以设置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;
  }
}

恕我直言,它应该可以正常工作(如果您有其他意见,请发表您的评论和批评)。但是我想知道如果我volatile从布尔值中删除修饰符会发生什么isNull(当然保留它instance)?它还能正常工作吗?

4

2 回答 2

3

The above code has a race condition: instance may be set to the "real" null from the result of instanceProvider.get() before isNull has been set.

Are you sure it wouldn't be easier for you to just scrap this complicated nonsense and synchronise properly. I bet you will not be able to measure any difference in performance and it will be easier to verify that your code is correct.

于 2011-06-22T19:01:38.887 回答
2

As pointed out by Neil Coffey, this code contains a race condition, but it can be easily fixed as follows (note that instance don't need to be volatile):

public class LazyReference<T> {     
  private T instance;
  private volatile boolean initialized;
  ...
  public T get() {
    if (!initialized) {
      synchronized (LOCK) {
        if (!initialized) {
          instance = instanceProvider.get();
          initialized = true;
        }
      }
    }
    return instance;
  }
}
于 2011-06-22T19:29:47.280 回答