单例对象 - 在静态块中或在 getInstance() 中;应该使用哪个

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

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

静态初始化:

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
6个回答
10
投票
  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;
        }
    }
    
    • 懒加载
    • 高性能
    • 不能用于非静态类字段

6
投票

第一个是热切初始化。 急切的初始化甚至在使用实例之前就创建实例,这不是最佳实践。

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

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


1
投票

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

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

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


1
投票

让你的班级像这样

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();

1
投票

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

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

更多详情请点击这里: https://twasink.net/2006/07/07/how-not-to-handle-exceptions-from-static-code-block-in-java/


0
投票

如果您需要在应用程序启动时初始化一些东西,请使用静态块。 f.ex,人们可能想从某个文件中加载一些有用的属性......等等

    static {
    instance = new Singleton();
    loadStuff();
}

使用延迟初始化

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

并且 loadStuff 仅在首次调用

Singleton.getInstance()
时才会被触发。

© www.soinside.com 2019 - 2024. All rights reserved.