我刚刚在某处阅读了以下代码:
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
关键字,这个成语才真正起作用。
不用说,正确执行单例模式并不是一件小事。
另见
- developerWorks/Java: Double-checked locking and the Singleton pattern -- A comprehensive look at this broken programming idiom
- Wikipedia/Double-checked locking
相关问题
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 实现:
- Efficient way to implement singleton pattern in Java
- Java Enum Singleton
- Comparing Java enum members: == or equals() ?
- Thread safety in Singleton
关于单例模式的优点和替代方案:
关于java - java中的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3272788/