/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.util.internal; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.BasicConstant.*; import static com.alibaba.citrus.util.ClassUtil.*; /** * 延迟加载对象。 * <p> * 目前有三种可用的加载方案,各方案的性能因JDK和环境而异: * </p> * <ol> * <li>同步的(Synchronized) - 最慢,但最经典可靠。</li> * <li>基于线程的(PerThread) - 比第一种快5-50倍左右,理论上也是可靠的。</li> * <li>基于DCL的(Double-Checked Locking) - 比第一种快5-70倍左右,理论上不可靠,但在JDK5以后应该没有问题了。</li> * </ol> * * @author Michael Zhou */ public abstract class LazyLoader<T, C> { private final Loader<T, C> loader; protected LazyLoader(Loader<T, C> loader) { this.loader = assertNotNull(loader); } public final T getInstance() { return getInstance(null); } public abstract T getInstance(C context); public abstract boolean testInstance(); /** 调用loader装载对象。 */ protected final T load(C context) { try { return loader.load(context); } catch (RuntimeException e) { if (loader instanceof ExceptionHandler<?, ?>) { return ((ExceptionHandler<T, C>) loader).handle(e, context); } else { throw e; } } } /** 用来创建对象实例。 */ public static interface Loader<T, C> { T load(C context); } public static interface ExceptionHandler<T, C> extends Loader<T, C> { T handle(RuntimeException e, C context); } /** 取得默认的方案。 */ public static <T, C> LazyLoader<T, C> getDefault(Loader<T, C> loader) { return getDoubleCheckedLockingLazyLoader(loader); } /** * 用保守的同步方法来创建对象。 * <p> * 该方案在任何JVM中都是安全的。 * </p> */ public static <T, C> LazyLoader<T, C> getSynchronizedLazyLoader(Loader<T, C> loader) { return new LazyLoader<T, C>(loader) { private boolean loaded; private T instance; @Override public T getInstance(C context) { synchronized (this) { if (!loaded) { instance = load(context); loaded = true; } } return instance; } @Override public synchronized boolean testInstance() { return loaded; } }; } /** * 利用<code>ThreadLocal</code>来标记当前线程是否完成了同步操作,从而实现延迟装载。 * <p> * 该方案在任何JVM中都是安全的。 * </p> */ public static <T, C> LazyLoader<T, C> getPerThreadLazyLoader(Loader<T, C> loader) { return new LazyLoader<T, C>(loader) { private final ThreadLocal<Boolean> synced = new ThreadLocal<Boolean>(); private boolean loaded; private T instance; @Override public T getInstance(C context) { if (synced.get() == null) { synchronized (this) { if (!loaded) { instance = load(context); loaded = true; } } synced.set(Boolean.TRUE); } return instance; } @Override public boolean testInstance() { if (synced.get() == null) { synchronized (this) { if (loaded) { synced.set(Boolean.TRUE); } return loaded; } } else { return true; } } }; } /** * 利用<code>volatile</code>变量的特性,以DCL的方式进行装载。 * <p> * 注意,该实现理论上比<code>SynchronizedLazyLoader</code>有更好的性能,但其正确性取决于JVM的实现。<br> * 一般认为,JDK5以后,支持对<code>volatile</code>变量的DCL操作。 * </p> */ public static <T, C> LazyLoader<T, C> getDoubleCheckedLockingLazyLoader(Loader<T, C> loader) { return new LazyLoader<T, C>(loader) { private volatile boolean loaded; private volatile T instance; @Override public T getInstance(C context) { if (!loaded) { synchronized (this) { if (!loaded) { instance = load(context); loaded = true; } } } return instance; } @Override public boolean testInstance() { return loaded; } }; } /** 转换成字符串表示。 */ @Override public String toString() { return String.format("LazyLoader(%s%s)", getSimpleClassName(loader.getClass()), testInstance() ? ", loaded" : EMPTY_STRING); } }