Singleton lazy vs eager instantiation

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Singleton lazy vs eager instantiation相关的知识,希望对你有一定的参考价值。

如果单例实现如下,

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

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

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

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

我错过了什么吗?

答案

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

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
另一答案

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

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

请参考IBM的Singleton + Lazy Loading + Multithreaded Environment案例中的tutorial

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

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

另一答案

由于你提到的原因,这只是一种更复杂的做法

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
另一答案

首先,单例模式被过度使用。如果你想要“一件事”,你真正想要做的就是在你选择的DI框架中宣布它是一个单身人士。这实际上是一个配置驱动的急切单例,并释放注入模拟的选项以进行适当的测试。

为什么不懒加载?除非你的类在构造中有一个大规模的初始化例程(我认为这也是一个反模式),所以延迟加载没有任何好处和许多缺点。如果没有正确完成,你只是增加了复杂性并可能破坏你的程序。正确的方法(如果必须)是使用按需初始化持有者惯用法。

另一答案

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

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;
}
}

以上是关于Singleton lazy vs eager instantiation的主要内容,如果未能解决你的问题,请参考以下文章

[Hibernate] - EAGER and LAZY

SQLAlchemy lazy load和eager load

学说中 fetch="EAGER" 和 fetch="LAZY" 有啥区别

EF6 中的 Eager 、 Lazy 和显式加载

CDI + JPA 多个 @OneToMany - LAZY/EAGER - LazyInitializationException 或无法实例化多个包

SQL Lazy Spool Eager Spool