单例模式是为了保证一个类仅提供一个可以使用的对象。
在单例模式中采用双重校验锁,可以提升性能和保证线程安全。
- 第一重校验锁:为了提高性能。如果没有第一重校验锁,那么每次调用 getInstance()
方法都要先获取锁下能进入,如果之前已经创建过一个对象,没有第一重校验锁,只有竞争到锁进入方法才知道对象已存在,就会大大的浪费性能。而有了第一重校验锁,只需要判断一下对象是否为空就能够知道对象有没有实例化,不需要再去竞争锁。 - 第二重校验锁:为了保证线程安全。如果有多个线程运行到synchronized代码块,只有一个线程能够竞争到锁,然后实例化对象,释放锁。此时如果没有第二重校验锁,之前没有竞争到锁的线程如果竞争锁进入代码块,都会实例化一次对象,因此不能保证线程安全。所以在多线程的情况下,第二重校验锁也是必不可少的。
public class Singleton {
private volatile static Singleton instance = null;
//构造函数私有,防止被实例化
private Singleton(){}
public static Singleton getInstance() {
//一重校验
if (instance == null) {
synchronized (Singleton.class) {
//二重校验
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}