0%
[build by hexo/next/gitalk/hexo-generator-search/LaTeX]">
单例模式(Java)
- 懒汉
- 第一次调用
getInstance()
方法时初始化对象
- 会有线程安全问题。两个线程同时获取对象,但是都还未初始化完成,则会返回两个不同的对象。虽然可以对方法用 synchronized,但是每次获取都需要加锁,降低效率。
- 双重检查锁定
- 需要用 volatile 修饰对象,以免对象初始化的时候指令重排。如下所示,如果 2 和 3 之间重排,则另一个线程可能会获得一个还未初始化的对象。
- 分配对象的内存空间
- 初始化对象
- 设置 uniqueInstance 指向刚分配的内存地址
- 饿汉
- 在类加载的时候直接创建这个对象,这样既能提高效率,又能保证线程安全。
- 静态内部类
- 饿汉式的方式只要 Singleton 类被装载了,那么 uniqueInstance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,uniqueInstance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有显示通过调用 getInstance 方法时,才会显示装载 SingletonHolder 类,从而实例化 uniqueInstance
- 枚举
- 用枚举实现单例模式可以避免如下 2 个问题,其他四种方式都不能避免
- 序列化造成单例模式不安全
- 反射造成单例模式不安全
- 如何防止反射、克隆、序列化对单例模式的破环
- 防止反射破环(虽然构造方法已私有化,但通过反射机制使用
newInstance()
方法构造方法也是可以被调用):
- 首先定义一个全局变量开关 isFristCreate 默认为开启状态
- 当第一次加载时将其状态更改为关闭状态
- 防止克隆破环
- 防止序列化破环
- 添加
readResolve()
,返回 Object 对象