【问题标题】:Singleton object- In static block or in getInstance(); which should be used单例对象 - 在静态块或 getInstance() 中;应该使用哪个
【发布时间】:2014-04-25 04:54:03
【问题描述】:

以下是实现单例的两种方法。各有什么优缺点?

静态初始化:

class Singleton {
    private Singleton instance;
    static {
        instance = new Singleton();
    }
    public Singleton getInstance() {
        return instance;
    }
}

延迟初始化是:

class Singleton {
    private Singleton instance;
    public Singleton getInstance(){
        if (instance == null) instance = new Singleton();
        return instance;
    }
}

【问题讨论】:

  • 注意:静态块只能直接访问在静态块外部定义的静态变量

标签: java static singleton lazy-initialization static-block


【解决方案1】:
  1. 同步存取器

    public class Singleton {
        private static Singleton instance;
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    • 延迟加载
    • 性能低下
  2. 双重检查锁定和易失性

    public class Singleton {
        private static volatile Singleton instance;
        public static Singleton getInstance() {
            Singleton localInstance = instance;
            if (localInstance == null) {
                synchronized (Singleton.class) {
                    localInstance = instance;
                    if (localInstance == null) {
                        instance = localInstance = new Singleton();
                    }
                }
            }
            return localInstance;
        }
    }
    
    • 延迟加载
    • 高性能
    • JDK 应该是 1,5 ++
  3. 随需应变的成语

    public class Singleton {
    
        public static class SingletonHolder {
            public static final Singleton HOLDER_INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance() {
            return SingletonHolder.HOLDER_INSTANCE;
        }
    }
    
    • 延迟加载
    • 高性能
    • 不能用于非静态类字段

【讨论】:

    【解决方案2】:

    第一个是急切初始化。 急切初始化甚至在实例被使用之前就创建了它,这不是最好的做法。

    第二个是延迟初始化。 惰性实现在单线程环境下工作得很好,但是对于多线程系统,如果多个线程同时在 if 循环中,它可能会导致问题。它将破坏单例模式,两个线程将获得单例类的不同实例。

    更多信息请访问:http://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-with-examples#static-block-initialization

    【讨论】:

    • 单例模式的精彩示例。 Threadsafe 似乎是最好的选择。糟糕,反射只会破坏
    【解决方案3】:

    注意:静态块只能直接访问在静态块外部定义的静态变量。您希望限制为仅创建一个实例的对象应该是静态。您的第一种方法在编译期间失败,第二种方法需要您先创建对象
    请遵循此方法:

    class Singleton
    {
    private static Singleton instance;
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if(instance == null)
             instance = new Singleton();
        return instance;
    }
    }
    

    确保不会在其他地方创建对象,因此将构造函数更改为私有

    【讨论】:

      【解决方案4】:

      让你的课像这样

      public class Singleton {
      
      private Singleton() {
      
      }
      
      private static Singleton instance;
      
      public static Singleton getInstance() {
          if (instance == null) {
              instance = new Singleton();
          }
          return instance;
      }
      
      }
      

      并称它为..

      Singleton instance = Singleton.getInstance();
      

      【讨论】:

      • 到目前为止,我使用的是第二种方法但是在一些代码中我也看到了这种方法。所以,我无法决定第一个何时有益。
      • @user2155922 第一个与我发布的一些修改相同..但您的代码实例中有一个错误位于静态块中,因此它必须是静态字段
      • @user2155922 并且当涉及到第二个方法时,它在您的 getInstance 方法是静态的之前是无效的。否则您需要创建对象来访问 getInstance() 方法,那么这不是单例..
      • 这发生在输入问题时...当我输入问题时它发生了。
      【解决方案5】:

      静态初始化程序不能抛出异常并将 RuntimeExceptions 吸收到 ClassDefNotFoundException 中,这不会停止执行。所以你可以看到很多 ClassDefNotFoundException 在您的日志中,您甚至可能直到很久以后才意识到有问题,因为执行仍在继续。

      第二种方法允许 RuntimeExceptions 停止执行。

      更多细节在这里: https://twasink.net/2006/07/07/how-not-to-handle-exceptions-from-static-code-block-in-java/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-28
        • 1970-01-01
        • 1970-01-01
        • 2016-11-13
        • 1970-01-01
        相关资源
        最近更新 更多