Java 中惰性线程安全单例实例化的模式

懒惰线程安全的单例实例对于每个编码人员来说都不容易理解,所以我想在我们的企业框架中创建一个类来完成这项工作。

对此,你怎么看?你看到它有什么不好吗?在Apache Commons中是否有类似的东西?我怎样才能让它变得更好?

供应商.java

public interface Supplier<T> {
    public T get();
}

LazyThreadSafeInstantiator.java

public class LazyThreadSafeInstantiator<T> implements Supplier<T> {
    private final Supplier<T> instanceSupplier;

    private volatile T obj;

    public LazyThreadSafeInstantiator(Supplier<T> instanceSupplier) {
        this.instanceSupplier = instanceSupplier;
    }

    @Override
    // http://en.wikipedia.org/wiki/Double-checked_locking
    public T get() {
        T result = obj;  // Wikipedia: Note the usage of the local variable result which seems unnecessary. For some versions of the Java VM, it will make the code 25% faster and for others, it won't hurt.
        if (result == null) {
            synchronized(this) {
                result = obj;
                if (result == null) {
                    result = instanceSupplier.get();
                    obj = result;
                }
            }
        }
        return result;
    }
}

用法示例:

public class Singleton1 {
    private static final Supplier<Singleton1> instanceHolder =
        new LazyThreadSafeInstantiator<Singleton1>(new Supplier<Singleton1>() {
            @Override
            public Singleton1 get() {
                return new Singleton1();
            }
        });

    public Singleton1 instance() {
        return instanceHolder.get();
    }

    private Singleton1() {
        System.out.println("Singleton1 instantiated");
    }
}

谢谢


答案 1

懒惰线程安全的单例实例对于每个编码人员来说都不容易理解

不,这实际上非常非常容易:

public class Singleton{
    private final static Singleton instance = new Singleton();
    private Singleton(){ ... }
    public static Singleton getInstance(){ return instance; }
}

更好的是,让它成为一个枚举:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}

它是线程安全的,而且是懒惰的(初始化发生在类加载时,Java在第一次引用它们之前不会加载类)。

事实是,99%的时间你根本不需要延迟加载。在剩下的1%中,在0.9%中,上述是完全懒惰的。

您是否运行了探查器并确定您的应用程序达到 0.01% 的优先级,而该应用确实需要首次加载延迟访问?不以为然。那么,你为什么要浪费时间炮制这些令人憎恶的Rube Goldbergesque代码来解决一个不存在的问题呢?


答案 2

对于一个比问题中介绍的版本更具可读性(在我看来),可以参考Bill Pugh引入的初始化按需持有者成语。考虑到Java 5内存模型,它不仅是线程安全的,而且单例也被懒惰地初始化。