2007年11月8日星期四

Singleton 的一些实现方式

使用单件模式的好处主要就是为了提高效率,节省资源
有两种实现方式:
一种是 lazy initialization, 只是 Singleton 实例只有使用时才创建
另一种是 early initialization,就是 Singleton 实例所在的类初始化的时候,Singleton 实例就已经创建

1. 推荐方式(lazy intialization)
但这种方式的缺点是只能用于静态域,不能用于实例域
public class Singleton {

static class SingletonHolder {
static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.instance;
}
}


2. 比较传统的实现方式(lazy intialization)
这种方式的缺点是每次调用都会使用同步,造成较大的资源开销
public class Singleton{
static Singleton instance;

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

3. 最臭名照著的 DCL(double-checked-locking Model),看上去很美,但不能正常工作(lazy intialization)
在 jdk1.4 的 Java Memory Model 下不能正常工作,但在 jdk 1.5 下做改进后则可以正常工作,见下一种实现方式
这种方式从代码上看去的好处:不会每次调用都使用同步,只有第一次使用时才会使用同步
不能正常工作的原因:多线程调用时,当其中一个线程调用该引用对象上的方法时,那个方法可能会看到该对象被部分初始化的状态,从而导致灾难性的失败

对于某些编译器来说,可能会允许调用被部分实例化的对象的共享变量。这样,在多线程的时候,可能线程A正在实例化对象到一半的时候,线程B就开始调用对象的某些方法或访问变量了,这样就会导致失败。

public class Singleton{
private static Singleton instance = null;

public Singleton getInstance() {
if (instance == null) {
synchronized (this) {
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}

4. 在上一种实现方式上做了改动,区别只是变量用了 volatile 关健字(lazy initialization)
只有在 jdk1.5 下才可以正常工作
效率上,第二种实现方式中的 synchronize 会慢点,但据说如果用 volatile 的话(第 4 种),比 synchronize 更慢,第一种效率更高

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

5. 这种方式是 early initailization
这种方式调用速度更块,但对资源的占用来说,由于是 early initialization 不一定是最好
public class Singleton{
private static final Singleton instance = new Singleton();
public Singleton getInstance(){
return instance;
}
}


另外,关于同步方法的效率,原文是这样的:synchronizing a method can decrease performance by a factor of 100 or higher;
我理解是可能会降低一倍或更高,不知道对不对?

关于 DCL 参考:http://en.wikipedia.org/wiki/Double-checked_locking

参考文章:
http://crazybob.org/2007/01/lazy-loading-singletons.html
http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl

没有评论: