1、普通单例
public class Singleton {
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
问题所在:
- 线程不安全
2、线程安全的单例1
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static synchronized Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
通过增加synchronized关键字到getInstance()方法中,迫使每个线程在进入方法之前,要先等别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。
问题所在:
- 对1中的单例进行线程安全优化,但同步方法getInstance依然存在实例被创建后重复进入同步方法getInstance,除第一次外,均造成资源浪费
- 在调用getInstance方法后才正式创建实例
3、线程安全的单例2
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
通过调整实例创建的方法在类构造后马上创建实例,提升实例创建速度
问题所在:
在侧重实例返回响应速度的情况下牺牲性能,使用全局静态实例,大大增加消耗
4、双重校验锁单例
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if(uniqueInstance == null) { //(1)
//只有第一次才彻底执行这里的代码
synchronized() {
//再检查一次
if(uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
优化点:
- volatile保证多线程的实例uniqueInstance正确获取
- synchronized块中代码只在第一次创建实例的时候完整执行,其余线程执行到(1)后等待获取到锁,当进入同步时其它线程已经创建了实例,跳出同步块直接返回实例
- 既满足了线程安全又满足性能上相对优化