单例惰性实例化与急切实例化

问题描述 投票:0回答:5

如果单例实现如下,

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

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

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

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

我在这里错过了什么吗?

java singleton lazy-initialization
5个回答
28
投票

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

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

请参考IBM关于单例+延迟加载+多线程环境案例的教程

================编辑于2018年9月9日=====================

您还应该查看按需创建对象模式这里


19
投票

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

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

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

1
投票

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

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


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;
}
}
© www.soinside.com 2019 - 2024. All rights reserved.