java中的惰性单例初始化

java中的惰性单例初始化,java,singleton,Java,Singleton,我们都知道lazy init singleton的一个古老而著名的习惯用法: public class Singleton { private static volatile Singleton instance; private Singleton() { // init... } public static Singleton getInstance() { if (instance == null) {

我们都知道lazy init singleton的一个古老而著名的习惯用法:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton()
    {
        // init...
    }

    public static Singleton getInstance()
    {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }

        return instance;
    }
}
但是,以下习惯用法本质上也是惰性的,因为只有在类装入器第一次访问该类时,实例才会是init:

public class Singleton
{
    private static final Singleton instance = new Singleton();

    private Singleton()
    {
        // init..
    }

    public static Singleton getInstance()
    {
        return instance;
    }
}
所以问题是,为什么我们要使用第一个例子而不是第二个?(不是说最好使用spring之类的框架来管理对象的生命周期。)

即使您在另一个类中持有对singleton的引用,如下所示:

public class Holder {
   private int member1;
   private int member2;
   private Singleton myService = Singleton.getInstance();

}
无论我们采用哪种方法,单例都将在Holder类加载时创建

有什么见解吗?
谢谢这样的东西怎么样

public class Singleton {
    ...
    public static int getSomeStaticInfo() { return 42; }
    ...
} 

public class Holder {
    private int member1;
    private int member2 = Singleton.getSomeStaticInfo();
    private Singleton myService;

    public void init() {
        myService = Singleton.getInstance();
    }
}

初始化单例时的行为在两个版本之间有所不同。这就是版本1展示正确行为的地方(就我们说“懒惰”时想要的行为而言)。加载类并不意味着要初始化它。

是。这是有道理的。我还没想过。我正在做标记作为答案。谢谢,事实上,这也不正确。我刚刚调试了这两个案例。在这两种方法中,只有在调用getInstance()方法后,才会加载Singleton类。对不起,我会编辑一秒钟。@现在解决方案应该不同了。您可以加载该类而不运行
getInstance()
code。是的,在这种情况下,您是对的。不过,这很奇怪,第二种方法并不是懒惰的,因为当类被引用时,实例就被初始化了。对于“真正的”惰性,应该在使用实例本身时初始化实例,而不仅仅是在加载类时。为什么要将我的问题标记为重复?我不是在寻找最有效的方法。这只是一个理论问题。至于我的理解,两者之间没有区别。您错了,因为只有在您使用该类时才会加载该类,即调用该类上的方法或访问其成员。唯一没有涉及的案例是尼尔提到的一个,我已经多次讨论过同样的问题(通常是来自没有经验的人的“你错了”的说法)。您的理解是错误的,副本很好地包含了所有不同的单例模式,包括现代的
enum
one和旧的内部类惰性加载程序。这里真的没有什么可讨论的。好的,你能详细说明我为什么错了吗?如果您只是在另一个类中声明了Singleton类的一个成员,那么在您实际使用该类(即调用一个方法,访问一个成员)之前,它不会被加载。如果这是错误的…这是您正在寻找的模式:。