38

如果单例实现如下,

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

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

这个实现与惰性初始化方法有什么不同?在这种情况下,将在加载类时创建实例,并且仅在第一次活动使用时才加载类本身(例如,Singleton.getInstance() 而不是在您声明例如 Singleton singleton = null; 时)

即使使用惰性初始化方法,实例也是在调用 getInstance() 时创建的

我在这里错过了什么吗?

4

5 回答 5

27

使用延迟初始化,您仅在需要时创建实例,而不是在加载类时。因此,您可以避免不必要的对象创建。话虽如此,还有其他事情需要考虑。在惰性初始化中,您提供一个公共 API 来获取实例。在多线程环境中,避免不必要的对象创建带来了挑战。您放置了造成不必要锁定的同步块,以检查已创建的对象。所以在这种情况下它成为一个性能问题。

因此,如果您确定创建对象不会占用任何大量内存并且它几乎总是会在您的应用程序中使用,那么最好在静态初始化中创建。另外请不要忘记在这种情况下使您的实例成为最终实例,因为它确保对象创建正确地反映到主内存中,这在多线程环境中很重要。

请参考IBM 提供的关于 Singleton+ Lazy Loading+ 多线程环境案例的教程

===============编辑于 09/09/2018====================

您还应该在此处查看按需创建对象模式。

于 2011-10-17T06:51:51.177 回答
17

您也可以调用任何其他静态方法或静态成员变量来加载单例实例。

class Logger {     
   private static Logger instance = new Logger(); 
   public static String LOG_LINE_SEPERATOR =  
      System.getProperty("line.separator");
   public static Logger getInstance() {  
          return instance;     
   } 

   public static String logPattern() {
       return null;
   }
} 

...

Logger.LOG_LINE_SEPERATOR; // load Logger instance or
Logger.logPattern(); // load Logger instance
于 2011-10-17T07:00:26.340 回答
8

由于您提到的原因,这只是一种更复杂的方式,与

enum Singleton {
    INSTANCE;
}

仅当您担心类可能会被初始化但您不想在此时加载单例时,使用延迟初始化才有用。在大多数情况下,这是过度杀戮。

注意:仅引用类不会初始化类。

例如,假设您有一个写得不好的类,在设置某些条件之前无法初始化。在这种情况下n必须为非零。

public class Main {
    public static void main(String ... args) {
        Class c= LazyLoaded.class;
        System.out.println(c);
    }

    static class LazyLoaded {
        static int n = 0;
        static {
            System.out.println("Inverse "+1000/n);
        }
    }
}

印刷

class Main$LazyLoaded
于 2011-10-17T07:47:28.697 回答
1

首先,单例模式被过度使用。如果您想要“某物之一”,您真正想做的是在您选择的 DI 框架中将其声明为单例。这实际上是一个配置驱动的渴望单例,并释放了注入模拟以进行适当测试的选项。

为什么不延迟加载?除非您的类在构造中具有大量的初始化例程(我认为这也是一种反模式),否则延迟加载没有任何好处和很多缺点。你只是增加了复杂性,如果没有正确完成,可能会破坏你的程序。正确的方法(如果必须的话)是使用 Initialization-on-demand 持有者习语。

于 2017-10-19T19:02:32.933 回答
0

对于延迟加载单例实例,我使用如下。

class Singleton {
private static Singleton instance;
private Singleton(){

}
public static Singleton getInstance() {
    if(null==instance){
        synchronized(Singleton.class){
            if(null==instance){
                instance = new Singleton();
            }
        }
    }
    return instance;
}
}
于 2018-01-04T07:46:24.780 回答