本文主要介紹如何利用Guava的Suppliers.memoize實現單例。java
/** * 利用Suppliers.memoize實現單例 * Created by xixicat on 15/12/25. */ public class SuppilerSingletonTest { class HeavyObject{ public HeavyObject() { System.out.println("being created"); } } class ObjectSuppiler implements Supplier<HeavyObject>{ @Override public HeavyObject get() { return new HeavyObject(); } } /** * 每次都new一次 */ @Test public void testNotSingleton(){ Supplier<HeavyObject> notCached = new ObjectSuppiler(); for(int i=0;i<5;i++){ notCached.get(); } } /** * 單例 */ @Test public void testSingleton(){ Supplier<HeavyObject> notCached = new ObjectSuppiler(); Supplier<HeavyObject> cachedSupplier = Suppliers.memoize(notCached); for(int i=0;i<5;i++){ cachedSupplier.get(); } } }
/** * Returns a supplier which caches the instance retrieved during the first * call to {@code get()} and returns that value on subsequent calls to * {@code get()}. See: * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a> * * <p>The returned supplier is thread-safe. The supplier's serialized form * does not contain the cached value, which will be recalculated when {@code * get()} is called on the reserialized instance. * * <p>If {@code delegate} is an instance created by an earlier call to {@code * memoize}, it is returned directly. */ public static <T> Supplier<T> memoize(Supplier<T> delegate) { return (delegate instanceof MemoizingSupplier) ? delegate : new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate)); } @VisibleForTesting static class MemoizingSupplier<T> implements Supplier<T>, Serializable { final Supplier<T> delegate; transient volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs // on volatile read of "initialized". transient T value; MemoizingSupplier(Supplier<T> delegate) { this.delegate = delegate; } @Override public T get() { // A 2-field variant of Double Checked Locking. if (!initialized) { synchronized (this) { if (!initialized) { T t = delegate.get(); value = t; initialized = true; return t; } } } return value; } @Override public String toString() { return "Suppliers.memoize(" + delegate + ")"; } private static final long serialVersionUID = 0; }