最近被问到单例为什么一定要进行两次非空的判断?我当时大脑就不转了!晚上我围着小区散散步忽然想起了这个问题,我静静的思考了下,其实我是能答的,但是当时头昏脑涨的就一下乱套了,所以遇到事情还是不要慌,先梳理下基础知识冷静的分析下。
首先我们看看单例双重检验的代码实现:
public class SingleInstance {
private static volatile SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (instance == null) { //第一层
synchronized (SingleInstance.class) {
if (instance == null) { //第二层
instance = new SingleInstance();
}
}
}
return instance;
}
}
getInstance()方法第一层非空判断其实就是使用缓存的思想,过滤掉重复竞争锁的逻辑。我们不妨去掉这行代码:
public class SingleInstance {
private static volatile SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
synchronized (SingleInstance.class) {
if (instance == null) {
instance = new SingleInstance();
}
}
return instance;
}
}
这是不是就一目了然了,要是没有第一次非空判断,每次都会走竞争锁的逻辑,也是不必要的资源开销。
再讨论下getInstance()方法的第二层非空判断,它的作用就是阻止多线程的情况下重复创建实例对象。我们不妨去掉这行代码:
public class SingleInstance {
private static volatile SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (instance == null) {
synchronized (SingleInstance.class) {
instance = new SingleInstance();
}
}
return instance;
}
}
此时可以看出要是多线程的情况下,多个线程都走到了竞争锁的位置,当第一个线程执行完后释放锁,另外的线程拿到锁还能继续创建对象,此处加了一层非空判断就是规避了此问题。
网友评论