我正在阅读Dagger2的源代码,并且其中ScopedProvider
有一个静态字段UNINITIALIZED
,用于指示该instance
字段尚未初始化。我已经阅读并理解了double-check-lazy-initialization惯用语,但是为什么有必要定义该UNINITIALIZED
字段而不是仅仅使用null
?与JVM有关吗?
/**
* A {@link Provider} implementation that memoizes the result of a {@link Factory} instance.
*
* @author Gregory Kick
* @since 2.0
*/
public final class ScopedProvider<T> implements Provider<T> {
private static final Object UNINITIALIZED = new Object();
private final Factory<T> factory;
private volatile Object instance = UNINITIALIZED;
private ScopedProvider(Factory<T> factory) {
assert factory != null;
this.factory = factory;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the factory
@Override
public T get() {
// double-check idiom from EJ2: Item 71
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
instance = result = factory.get();
}
}
}
return (T) result;
}
/** Returns a new scoped provider for the given factory. */
public static <T> Provider<T> create(Factory<T> factory) {
if (factory == null) {
throw new NullPointerException();
}
return new ScopedProvider<T>(factory);
}
}
看起来这是一个懒惰的null安全初始化。想象一下,如果工厂返回的是null,而该代码而不是UNINITIALIZED则使用null作为标记值。每次调用get()都会进入同步块,因为它不知道null是否实际上是出厂结果,而不仅仅是未初始化的状态。
此代码允许工厂返回null并将结果正确存储在volatile字段中,以便后续读取不会产生完全同步的开销。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句