java - java中的单例

标签 java static singleton lazy-loading

我刚刚在某处阅读了以下代码:

public class SingletonObjectDemo {

    private static SingletonObjectDemo singletonObject;
    // Note that the constructor is private
    private SingletonObjectDemo() {
        // Optional Code
    }
    public static SingletonObjectDemo getSingletonObject() {
        if (singletonObject == null) {
            singletonObject = new SingletonObjectDemo();
       }
       return singletonObject;
    }
}

我需要知道这部分的需求是什么:

if (singletonObject == null) {
    singletonObject = new SingletonObjectDemo();
}

如果我们不使用这部分代码怎么办?仍然会有一个 SingletonObjectDemo 副本,那我们为什么需要这段代码?

最佳答案

惰性初始化与急切初始化

if 语句是 lazy initialization 的一个实现技术。

更明确的版本如下:

private boolean firstTime = true;
private Stuff stuff;

public Stuff gimmeStuff() {
   if (firstTime) {
      firstTime = false;
      stuff = new Stuff();
   }
   return stuff;
}

发生的事情是第一次调用 gimmeStuff() 时,firstTime 将为 true,所以 stuff 将被初始化为 new Stuff()。在后续调用中,firstTime 将为 false,因此将不再调用 new Stuff()

因此,stuff 被“延迟”初始化。直到第一次需要它时才真正初始化它。

另见


关于线程安全

需要说明的是,该代码段不是线程安全的。如果有多个线程,那么在一些race conditions new SingletonObjectDemo() 可能被调用多次。

一个解决方案是制作同步的getSingletonObject() 方法。但是,这确实会对 ALL 调用 getSingletonObject() 产生同步开销。所谓double-checked locking然后使用成语来尝试解决这个问题,但在 Java 中,直到 J2SE 5.0 在新的内存模型中引入 volatile 关键字,这个成语才真正起作用。

不用说,正确执行单例模式并不是一件小事。

另见

相关问题


Effective Java 第二版

以下是本书关于这些主题的内容:

条款 71:明智地使用惰性初始化

As is the case for most optimizations, the best advice for lazy initialization is "don't do it unless you need to". Lazy initialization is a double-edged sword. It decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing a lazily initialized field. Depending on what fraction of lazily initialized fields eventually require initialization, how expensive it is to initialize them, and how often each field is accessed, lazy initialization (like many "optimizations" actually harm performance).

In the presence of multiple threads, lazy initialization is tricky. If two or more threads share a lazily initialized field, it is critical that some form of synchronization be employed, or severe bugs can result.

Under most circumstances, normal initialization is preferable to lazy initialization.

项目 3:使用私有(private)构造函数或enum 类型强制实现单例属性

As of release 1.5. there is a third approach to implementing singletons. Simply make an enum type with one element. [...] This approach is functionally equivalent to the public field approach, except that it's more concise, provides the serialization mechanism for free, and provides ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection-based attacks.

[...] A single-element enum type is the best way to implement a singleton.

相关问题

关于 enum 单例/Java 实现:

关于单例模式的优点和替代方案:

关于java - java中的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3272788/

相关文章:

java - 无可用连接时的 HikariCP 行为

java - Yaml文件读取对象歧义

java - 使用 Maven 从 jar 运行我的 testNG 项目

java - 如何为新的 WiFi 配置设置静态 IP?

swift - 如何访问枚举之外的属性

ios - Swift 框架或 Objective-c 库

java - 单例方法是否适合访问/维护数据库和互联网连接

java - 带属性的 Spring 单例

java - 在 Android/Java 中更改 XML 值

python - 为什么 Borg 模式比 Python 中的 Singleton 模式更好