@Yano
2016-07-20T22:26:30.000000Z
字数 3628
阅读 2394
Java
设计模式
在一个系统中,一个类只有一个
实例化的对象。
The singleton pattern is implemented by creating a class with a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object.
可以实现延迟加载
,即使用之前不占用内存或资源。(Note the distinction between a simple static instance of a class and a singleton: although a singleton can be implemented as a static instance, it can also be lazily constructed, requiring no memory or resources until needed.)
The singleton pattern must be carefully constructed in multi-threaded applications. If two threads are to execute the creation method at the same time when a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one. If the programming language has concurrent processing capabilities the method should be constructed to execute as a mutually exclusive operation. The classic solution to this problem is to use mutual exclusion on the class that indicates that the object is being instantiated.
使用“双重检查加锁”——double-checked locking
。其中变量 instance 是 volatile
的,1.4及更早的Java中,volatile关键字的实现会导致双重检查加锁的失效。具体原因,参考 The "Double-Checked Locking is Broken" Declaration 。
public final class SingletonDemo {
private static volatile SingletonDemo instance;
private SingletonDemo() { }
public static SingletonDemo getInstance() {
if (instance == null ) {
synchronized (SingletonDemo.class) {
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
}
在并发性并不是很高,性能并不特别需求的情况下,可以使用下面简洁的方法:
public final class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() { }
public static synchronized SingletonDemo getInstance() {
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
}
如果系统总是需要一个实例,或者创建实例的开销并不大,可以使用Eager initialization,它总是返回一个实例。
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
这种方法的好处:
getInstance()
不需要同步,所有的线程都会看到同样的实例。final
使得 INSTANCE 不能修改,保证有且只有
一个实例。在static代码块
中创建新实例,同Eager initialization
。
public final class Singleton {
private static final Singleton instance;
static {
try {
instance = new Singleton();
} catch (Exception e) {
throw new RuntimeException("Darn, an error occurred!", e);
}
}
public static Singleton getInstance() {
return instance;
}
private Singleton() {
// ...
}
}
延迟加载
所有
的 Java 版本线程安全
public final class Singleton {
// Private constructor. Prevents instantiation from other classes.
private Singleton() { }
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
内部类SingletonHolder
在方法getInstance()
被调用时,才会被 class loader 加载。因此这个方法是线程安全的,不需要额外的同步手段。内部类SingletonHolder
也可以被定义成final的。
In the second edition of his book Effective Java, Joshua Bloch claims that "a single-element enum type is the best way to implement a singleton" for any language that supports enums, like Java.
public enum Singleton {
INSTANCE;
public void execute (String arg) {
// Perform operation here
}
}
Java语言保证,枚举类型会在需要使用时,通过 class loader 加载。同时 Java 的枚举类型是全局可见的,但是有些呆板 0_o。