1. 概念
- 广义单例模式,就是在jvm中,共用一个类的唯一实例
- 狭义单例模式,即单例类,通过类本身去实现上述目的
2. 优缺点
优点
- 避免频繁的创建和销毁实例,这点对大对象犹为重要
缺点
- 单例类较难扩展,牵一发而动全身
- 单例类不能被继承,因为构造器私有
3. 应用
- 线程池、缓存、日志、配置文件、打印机/显卡等硬件设备的驱动程序对象等等
- Servlet、Spring、Strust2、SpringMVC、线程池等
4. 创建单例类
1. 饿汉式(推荐)
网上都说饿汉式在不用时浪费内存,扯蛋!实例是在类加载时的准备阶段分配内存的,你不用时,根本不会触发它的加载!
public class SingletonClass1 {
private static final SingletonClass1 INSTANCE = new SingletonClass1();
private SingletonClass1() {
}
public static SingletonClass1 getInstance() {
return INSTANCE;
}
}
简单安全,实例在类加载时创建,而虚拟机保证类加载时线程安全。
2. 懒汉式
线程不安全,基本不用
public class SingletonClass2 {
private static SingletonClass2 instance;
private SingletonClass2() {}
public static SingletonClass2 getInstance() {
if (instance == null) {
instance = new SingletonClass2();
}
return instance;
}
}
3. 懒汉式-同步方法
线程安全,但效率低
public class SingletonClass3 {
private static SingletonClass3 instance;
private SingletonClass3() {}
public static synchronized SingletonClass3 getInstance() {
if (instance == null) {
instance = new SingletonClass3();
}
return instance;
}
}
4. 懒汉式-双重检测-同步代码块(可用)
线程安全,延迟加载,效率高
public class SingletonClass4 {
private static SingletonClass4 instance;
private SingletonClass4() {
}
public static SingletonClass4 getInstance() {
if (instance == null) {
synchronized (SingletonClass4.class) {
if (instance == null) {
instance = new SingletonClass4(); // 1
}
}
}
return instance;
}
}
- 这种双重检测机制是有问题的,问题出在//1,由所谓的无序写入造成的。一般来讲,当初始化一个对象的时候,会经历内存分配、初始化、返回对象在堆上的引用等一系列操作,这种方式产生的对象是一个完整的对象,可以正常使用。但是JAVA的无序写入可能会造成顺序的颠倒,即内存分配、返回对象引用、初始化的顺序,这种情况下对应到//1就是singleton已经不是null,而是指向了堆上的一个对象,但是该对象却还没有完成初始化动作。当后续的线程发现singleton不是null而直接使用的时候,就会出现意料之外的问题。
- JDK1.5之后,可以使用volatile关键字修饰变量来解决无序写入产生的问题,因为volatile关键字的一个重要作用是禁止指令重排序,即保证不会出现内存分配、返回对象引用、初始化这样的顺序,从而使得双重检测真正发挥作用。
- synchronized也可以保证有序性,但不会禁止指令重排,所以synchronized内部改变的变量,被其它线程在外面使用,是有安全问题的
5. 静态内部类(可用)
线程安全、延迟加载、效率高
public class SingletonClass5 {
private static class InnerClass {
private static final SingletonClass5 INSTANCE = new SingletonClass5();
}
public static SingletonClass5 getInstance() {
return InnerClass.INSTANCE;
}
}
6. 枚举类(可用)
线程安全、效率高、防反射
public enum SingletonClass6 {
INSTANCE;
SingletonClass6() {
}
}