🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## **单例模式的定义与特点** 定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式 目的:为了节省内存资源、保证数据内容的一致性等 特点: 1. 单例类只有一个实例对象 2. 该单例对象必须由单例类自行创建 3. 单例类对外提供一个访问该单例的全局访问点 ## **单例创建方式** 1. 饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高,项目中常用的模式。 ``` public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() { } public static Singleton getInstance() { return singleton; } } ``` 2. 懒汉式:类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象 ``` public class Singleton { private static Singleton singleton; private Singleton() { } public synchronized static Singleton getInstance() { if (null == singleton) { singleton = new Singleton(); } return singleton; } } ``` 3. 静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的 ``` public class Singleton { private Singleton() { } // 静态内部类 private static class SingletonInstance { private static Singleton singleton = new Singleton(); } public static Singleton getInstance() { return SingletonInstance.singleton; } } ``` 4. 枚举单例:使用枚举实现单例模式(枚举本身就是单例) 5. 双重检测锁方式:懒汉模式的升级版 懒汉模式中加入synchronized锁,每次获取单例对象时都有读取锁的操作,性能必定大大降低,我们的目的只是想要在第一次创建实例的时候加锁就可以了,所以改造代码 ~~~ public class Singleton { private static Singleton singleton; private Singleton() { } public static Singleton getInstance() { if (null == singleton) { synchronized (Singleton.class) { if (null == singleton) { singleton = new Singleton(); } } } return singleton; } } ~~~ 初始化之后,后续再调用就不会有获取锁的操作,解决了性能的问题。看似很完美了,但是似乎哪里还有不多的地方,问题出在 singleton = new Singleton();这一过程可以分解成一下3步: ``` 1.分配内存空间 2.初始化对象 3.将对象指向刚分配的内存空间 ``` 多线程的情况的处理器会进行重排序,有可能执行顺序变成了1->3->2,那么多线程下的调用结果就变成了 | Thread A | Thread B | | --- | --- | | 检查到`singleton`为空 | | | 获取锁 | | | 再次检查到`singleton`为空 | | | 为`singleton`分配内存空间 | | | 将`singleton`指向内存空间 | | | | 检查到`singleton`不为空 | | | 访问`singleton`(此时对象还未完成初始化) | | 初始化`singleton` | | 最终 Thread B访问到了一个未初始化的对象,于是继续改善代码加入`volatile`关键字防止重排序 ~~~ public class Singleton { private volatile static Singleton singleton; private Singleton() { } public static Singleton getInstance() { if (null == singleton) { synchronized (Singleton.class) { if (null == singleton) { singleton = new Singleton(); } } } return singleton; } } ~~~