定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
三种写法:
(1)懒汉式
public class SingletonLazy {
private static SingletonLazy instance = null;
private SingletonLazy () {}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
优点:使用时才创建,节约资源
缺点: 线程不安全,因为多线程环境下,new SingletonLazy()可能会执行多次。
改进1:给getInstance()方法加锁。
public class SingletonLazy {
private static SingletonLazy instance = null;
private SingletonLazy () {}
public synchronized static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
问题:多线程环境下,虽然能保证单例,但是每个线程进入getInstance() 方法时,都会挂起其他的线程,即便SingletonLazy已经被实例化了,方法也不是立即返回,而synchronzized是有时间代价的,所以效率不高。
改进2:双重检查
public class SingletonDoubleCheck {
private static SingletonDoubleCheck instance = null;
private SingletonDoubleCheck () {}
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null)
instance = new SingletonDoubleCheck();
}
}
return instance;
}
}
优点:多线程环境下
1. 执行getInstance()方法时,不需要阻塞,如果SingletonDoubleCheck已经被创建,则方法迅速返回对象实例。这是第一层检查的的作用。
2. 只在SingletonDoubleCheck未被初始化的时候才加锁,这是比“改进1”效率高的地方。第二层检查的作用是保证单例。
问题:new SingletonDoubleCheck()不是一个“原子操作”,就是说这个操作需要n步才能完成,这里涉及一个JVM的话题——指令重排序,这就可能导致先修改了instance的值,再执行真正的构造方法。所以,还是有可能出现一个线程未出这个语句块时,另一个线程进入。(笔者对这个地方,还不太能解释清楚,先做个标记,后面完善)
改进3:加volatile
public class SingletonDoubleCheck {
private volatile static SingletonDoubleCheck instance = null;
private SingletonDoubleCheck () {}
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null)
instance = new SingletonDoubleCheck();
}
}
return instance;
}
}
(2)饿汉式
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry () {}
public static SingletonHungry getInstance() {
return instance;
}
}
优点:线程安全,由JVM load机制保证
缺点:过早浪费资源
(3) 静态内部类式(推荐使用)
public class Singleton {
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private Singleton() {}
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
}
优点:在使用时才创建实例对象,JVM机制。