1 /* 2 * Copyright (C) 2014 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package dagger.internal; 17 18 import dagger.Lazy; 19 import javax.inject.Provider; 20 21 /** 22 * A basic {@link Lazy} implementation that memoizes the value returned from a {@link Provider} 23 * using the double-check idiom described in Effective Java 2: Item 71. 24 * 25 * @author Gregory Kick 26 * @since 2.0 27 */ 28 // TODO(gak): Unify the duplicated code between this and ScopedProvider. 29 public final class DoubleCheckLazy<T> implements Lazy<T> { 30 private static final Object UNINITIALIZED = new Object(); 31 32 private final Provider<T> provider; 33 private volatile Object instance = UNINITIALIZED; 34 35 private DoubleCheckLazy(Provider<T> provider) { 36 assert provider != null; 37 this.provider = provider; 38 } 39 40 @SuppressWarnings("unchecked") // cast only happens when result comes from the factory 41 @Override 42 public T get() { 43 // to suppress it. 44 Object result = instance; 45 if (result == UNINITIALIZED) { 46 synchronized (this) { 47 result = instance; 48 if (result == UNINITIALIZED) { 49 instance = result = provider.get(); 50 } 51 } 52 } 53 return (T) result; 54 } 55 56 public static <T> Lazy<T> create(Provider<T> provider) { 57 if (provider == null) { 58 throw new NullPointerException(); 59 } 60 if (provider instanceof Lazy) { 61 @SuppressWarnings("unchecked") 62 final Lazy<T> lazy = (Lazy<T>) provider; 63 // Avoids memoizing a value that is already memoized. 64 // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L 65 // are different types using covariant return on get(). Right now this is used with 66 // ScopedProvider<T> exclusively, which is implemented such that P and L are always the same 67 // so it will be fine for that case. 68 return lazy; 69 } 70 return new DoubleCheckLazy<T>(provider); 71 } 72 } 73