单例模式

双重校验+volatile (线程安全)
public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {
    }

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

volatile可以禁止JVM的指令重排。比如instance = new Singleton();其实分三步:1. 为新实例分配内存 2. 初始化新实例 3. 将instance指向新实例的内存地址。由于JVM具有指令重排的特性,执行顺序有可能变成1>3>2。这在单线程环境下没问题,但多线程环境下会导致某线程获得未初始化的实例。如线程T1执行了1和3,此时T2调用getInstance()发现instance不为空并返回instance,但此时instance指向的空间还未初始化。

静态内部类 (线程安全)
public class Singleton {
    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

当调用getInstance()时内部类才被加载。

参考