两种用线程安全延迟初始化实现单例的方法

时间:2014-03-30 20:07:34

标签: java multithreading

静态方法和变量:

public class Singleton{

    private static Singleton singleton = null;

    private Singleton(){
    }

    public static synchronized Singleton getInstance(){
        if(singletion == null)
            singleton = new Singletion();
        return singleton;
    }
}

Java 1.5之后的第二个

public class Singleton{

    private static volatile Singleton singleton = null;

    private Singleton(){
    }

    public static Singleton getInstance(){
        if(singleton == null){
            synchronized(this){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

那么这两个线程安全代码的优缺点是什么?我们何时应该使用哪个?

6 个答案:

答案 0 :(得分:4)

第二个是线程安全的,但以下更简单,更快,因为它不需要同步块。

public enum Singleton {
    INSTANCE;
    // define fields and methods here.
}

访问

Singleton.INSTANCE.method();

注意:如果需要,枚举可以实现接口。

答案 1 :(得分:2)

这两种实现都是线程安全且有效的。

前者较短。它更具可读性和可维护性。

后者更快,而且速度也比大多数人想象的要快。根据Java VM的实现,读取 volatile 变量与在x86上读取非易失性变量一样快。这意味着开销仅在初始化期间发生。但是,只要单例被初始化,就没有任何开销。

如果性能真的是一个问题,你应该使用后者。否则使用前者,因为对可读性和可维护性的需求经常被低估。

答案 2 :(得分:0)

第二个'双重检查'单例更快,因为无论何时请求(尽管第一次调用),它都不需要获取锁定。无论如何,控制对象生命周期的最佳方法是使用依赖注入。

答案 3 :(得分:0)

执行线程安全单例的最安全方法是通过initialisation on demand holder idiom

public class Foo {
    private Foo() {}
    private static class Holder {
        private static final Foo INSTANCE = new Foo();
    }
    public static Foo getInstance() {
        return Holder.INSTANCE;
    }
}

这适用于没有正确支持volatile关键字的Java版本。关于这种模式的巧妙之处在于它仅在getInstance的第一次访问时使用隐式锁定。之后,访问不同步。这是由于Java中存储管理和静态加载的一个有趣的小怪癖。

答案 4 :(得分:0)

两个例子都是单例的懒惰初始化,即你在需要的时候初始化单例。第二个例子是double checked locking的一个例子,主要针对线程安全

答案 5 :(得分:-1)

第一个不是线程安全的。如果getInstancesynchronized,那么它将是线程安全的。

如果您需要线程安全,请使用第二个。

虽然有一个更为简单的第三种方式,但略有不同(Singleton在不同的时间创建):

public class Singleton{

    private static final Singleton singleton = new Singleton();

    private Singleton(){
    }

    public static Singleton getInstance(){
        return singleton;
    }
}