前面
主要参考了文章:
- 单例模式和多线程安全
http://blog.csdn.net/wuwei1984100/article/details/18979325
- Java 单例模式探讨
http://blog.csdn.net/xsl1990/article/details/16359407
饿汉式单例类可以在Java内实现, 但不易在C++ 内实现,因为静态初始化在C++ 里没有固定的顺序,因而静态的m_instance 变量的初始化与类的加载顺序没有保证,可能会出问题。这就是为什么GoF 在提出单例类的概念时,举的例子是懒汉式的。他们的书影响之大,以致Java 语言中单例类的例子也大多是懒汉式的。实际上,本书认为饿汉式单例类更符合Java 语言本身的特点。
Java单例模式相对来说比较简单,也容易理解。我看到的资料将Java单例模式分为了4类。他们分别是:预先加载法,延迟加载法,双重检测(考虑多线程) ,内部类单例(考虑多线程)。
1. 预先加载法
class S1 {
private S1() {
System.out.println("ok1");
}
private static S1 instance = new S1();
public static S1 getInstance() {
return instance;
}
}
优点:
- 线程安全的;
- 在类加载的同时已经创建好一个静态对象,调用时反应速度快。
缺点:
- 资源利用效率不高,可能getInstance永远不会执行到,但是执行了该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化了。
2. 延迟加载法 (考虑多线程)
延迟加载:initialization on demand。
class S2 {
private S2() {
System.out.println("ok2");
}
private static S2 instance = null;
public static synchronized S2 getInstance() {
if (instance == null) instance = new S2();
return instance;
}
}
优点:
- 资源利用率高,不执行getInstance就不会被实例,可以执行该类其他静态方法。
缺点:
- 第一次加载时发应不快 ,多线程使用不必要的同步开销大。
3. 双重检测(考虑多线程)
双重检测:initialization on demand double check。
class S3 {
private S3() {
System.out.println("ok3");
}
private static S3 instance = null;
public static S3 getInstance() {
if (instance == null) {
synchronized (S3.class) {
if (instance == null)
instance = new S3();
}
}
return instance;
}
}
优点:
- 资源利用率高,不执行getInstance就不会被实例,可以执行该类其他静态方法。
缺点:
- 第一次加载时发应不快 ,由于java 内存模型一些原因偶尔会失败。
4. initialization on demand holder (考虑多线程)
class S4 {
private S4() {
System.out.println("ok4");
}
private static class S4Holder {
static S4 instance = new S4();
}
public static S4 getInstance() {
return S4Holder.instance;
}
}
优点:
- 资源利用率高,不执行getInstance就不会被实例,可以执行该类其他静态方法。
缺点:
- 第一次加载时发应不快。
总结
一般采用1即可,若对资源十分在意也可考虑4,不要使用2,3了。