线程安全之单例模式

120 阅读1分钟

普通懒汉式

class Singleton {
    private Singleton(){}
    private static Singleton single = null;
    private static Singleton getInstance() {
        if (single == null) {
            single = new Singleton();
        }
        return single;
    }
}

在多线程环境下可能创建多个实例,当两个线程同时获取single时都为null,都会进入if条件,所以可能创建多个实例

synchronized实现同步

class Singleton {
    private static Singleton single = null;
    private Singleton() {}

    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (single == null) {
                single = new Singleton();
            }
        }
        return single;
    }
}

同时只有一个线程可以进入同步代码块,但是实际上只有第一次当single为null的时候才需要加锁,上面代码每次都要加锁,性能不高

doule-check单例模式
class Singleton {
    private static Singleton single = null;
    private Singleton() {}

    public static Singleton getInstance() {
        if (single == null) {
            synchronized (Singleton.class) {
                if (single == null) {
                    single = new Singleton();
                }
            }
        }
        return single;
    }
}

只有当single为null的时候才会进入同步块,解决了上面每次都要加锁的问题。但是还可能存在指令重排的问题。 single = new Singleton()可以分为几步:

  1. 给single分配空间
  2. 调用构造方法初始化single
  3. 将single指向分配的地址 正常顺序是1->2->3,如果指令重排后可能是1->3->2,那么在执行完3后single != null了,这时候2判断第一个if的时候为false,会直接返回single

加volatile

class Singleton {
    private volatile static Singleton single = null;
    private Singleton() {}

    public static Singleton getInstance() {
        if (single == null) {
            synchronized (Singleton.class) {
                if (single == null) {
                    single = new Singleton();
                }
            }
        }
        return single;
    }
}

加volatile防止指令重排