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

java中的惰性线程安全单例实例化模式,java,thread-safety,singleton,instantiation,lazy-evaluation,Java,Thread Safety,Singleton,Instantiation,Lazy Evaluation,懒惰的线程安全单例实例对于每个编码人员来说都有点不容易理解,所以我想在我们的企业框架中创建一个类来完成这项工作 你觉得怎么样?你看到它有什么不好的地方吗?Apache Commons中是否有类似的东西?我怎样才能做得更好 Supplier.java public interface Supplier<T> { public T get(); } 公共接口供应商{ 公众不能得到(); } lazythreadsafetinstantiator.java public cla

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

你觉得怎么样?你看到它有什么不好的地方吗?Apache Commons中是否有类似的东西?我怎样才能做得更好

Supplier.java

public interface Supplier<T> {
    public T get();
}
公共接口供应商{
公众不能得到();
}
lazythreadsafetinstantiator.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类lazythreadsafe实例化器实现供应商{
私人最终供应商实例供应商;
私人银行;
公共LazyThreadSafe实例化器(供应商实例供应商){
this.instanceSupplier=instanceSupplier;
}
@凌驾
// http://en.wikipedia.org/wiki/Double-checked_locking
公共部门得不到{
T result=obj;//Wikipedia:注意局部变量result的用法,这似乎是不必要的。对于某些版本的Java VM,它将使代码速度提高25%,而对于其他版本,它不会有任何影响。
如果(结果==null){
已同步(此){
结果=obj;
如果(结果==null){
结果=instanceSupplier.get();
obj=结果;
}
}
}
返回结果;
}
}
用法示例:

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{
私人静态最终供应商实例持有者=
新LazyThreadSafe实例化器(新供应商(){
@凌驾
公共单音1 get(){
返回新的Singleton1();
}
});
公共单例1实例(){
返回instanceHolder.get();
}
私人单音1(){
System.out.println(“单例1实例化”);
}
}

感谢您,JIT编译器和多核/处理器系统上的双重检查锁定模式和volatile的使用不是因为Java内存模型和无序执行的可能性吗


更一般地说,对于一个基本上可以正确实现的非常简单的模式来说,单例框架似乎有点过分了。

对于一个比问题中提出的版本更可读(我认为)的版本,可以参考Bill Pugh介绍的。考虑到Java 5内存模型,它不仅是线程安全的,而且singleton的初始化也是惰性的。

在我看来过于工程化了

我真的看不出有助手有什么帮助

首先,它使用了双重锁定的习惯用法,并且已经被一次又一次地证明是错误的

其次,如果您必须使用singleton,为什么不初始化静态final实例呢

public class Singleton1 {
    private static final Singleton1 instanceHolder =
        new Singletong1( );

    public Singleton1 instance() {
        return instanceHolder;
    }

    private Singleton1() {
        System.out.println("Singleton1 instantiated");
    }
}
这段代码是线程安全的,并且已经被证明是有效的

查看Vineet Reynolds的答案,了解何时需要在首次获取时初始化singleton实例。在许多情况下,我认为这种方法也是一种过分的手段

懒惰的线程安全单例 实例化有点不容易 理解每一个编码员

不,实际上非常非常简单:

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 goldbergsque代码来解决一个不存在的问题呢?

我同意其他的海报,并说这看起来确实有些过分,但我确实认为这是一个初级开发人员可能会犯的错误。我认为,由于构造singleton(如下所示)的供应商的行为在几乎所有情况下都是相同的,因此我会尝试将其作为默认行为放在
LazyThreadSafe实例化器中。每当您想要使用单例时,使用注释性内部类是非常混乱的

        @Override
        public Singleton1 get() {
            return new Singleton1();
        }
这可以通过提供一个重载构造函数来完成,该构造函数将类带到所需的单例

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

    private Class<T> toConstruct;

    private volatile T obj;

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

    public LazyThreadSafeInstantiator(Class<t> toConstruct) {
        this.toConstruct = toConstruct;
    }

    @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) {
                    if (instanceSupplier == null) {
                      try {
                        Constructor[] c = toConstruct.getDeclaredConstructors();
                        c[0].setAccessible(true);
                        result = c[0].newInstance(new Object[] {});
                      } catch (Exception e) {
                        //handle
                      }
                      result = 
                    } else {
                      result = instanceSupplier.get();
                    }
                    obj = result;
                }
            }
        }
        return result;
    }
}
public类lazythreadsafe实例化器实现供应商{
私人最终供应商实例供应商;
私人建筑类;
私人银行;
公共LazyThreadSafe实例化器(供应商实例供应商){
this.instanceSupplier=instanceSupplier;
}
公共LazyThreadSafe实例化器(类toConstruct){
this.toConstruct=toConstruct;
}
@凌驾
// http://en.wikipedia.org/wiki/Double-checked_locking
公共部门得不到{
T result=obj;//Wikipedia:注意局部变量result的用法,这似乎是不必要的。对于某些版本的Java VM,它将使代码速度提高25%,而对于其他版本,它不会有任何影响。
如果(结果==null){
已同步(此){
结果=obj;
如果(结果==null){
如果(instanceSupplier==null){
试一试{
构造函数[]c=toConstruct.getDeclaredConstructors();
c[0].setAccessible(true);
结果=c[0].newInstance(新对象[]{});
}捕获(例外e){
//处理
}
结果=
}否则{
结果=instanceSupplier.get();
}
obj=结果;
}
}
}
返回结果;
}
}
这样就可以这样使用了

private static final Supplier<Singleton1> instanceHolder =
    new LazyThreadSafeInstantiator<Singleton1>(Singleton1.getClass());
私有静态最终供应商实例持有者=
新的LazyThreadSafe实例化器(Singleton1.getC
Lazy<X> lazyX= new Lazy<X>(){
    protected X create(){
        return new X();
    }};

X x = lazyX.get();
abstract public class Lazy<T>
{
    abstract protected T create();

    static class FinalRef<S>
    {
        final S value;
        FinalRef(S value){ this.value =value; }
    }

    FinalRef<T> ref = null;

    public T get()
    {
        FinalRef<T> result = ref;
        if(result==null)
        {
            synchronized(this)
            {
                if(ref==null)
                    ref = new FinalRef<T>( create() );
                result = ref;
            }
        }
        return result.value;
    }
}