I’ve been using LazyReference class for a few years (not on a regular basis of course, but sometimes it is very useful). The class can be seen here. Credits go to Robbie Vanbrabant (class author) and Joshua Bloch with his famous “Effective Java 2nd edt.” (original code).
The class works correctly (in Java 5+) but there is one little potential issue. If instanceProvider returns null (well it must not according to Guice Provider.get() contract, but…) then on every execution of LazyReference.get() method the LOCK will be held and instanceProvider.get will be called over and over again. It looks like a good punishment for those who break the contracts (he-he), but what if one really needs to lazily initialize a field with the possibility to set the null value?
I modified LazyReference a little bit:
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;
}
}
IMHO it should work just fine (if you have another opinion please post your comments and criticisms). But I wonder what will happen if I remove the volatile modifier from isNull boolean (leaving it for instance of course)? Will it still work correctly?
As pointed out by Neil Coffey, this code contains a race condition, but it can be easily fixed as follows (note that
instancedon’t need to bevolatile):