我使用 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/