单例模式
在一个系统内部,一个类只有一个实例对象.
条件:
- 私有的构造方法,外部不可 new 对象
- 自己创建一个静态变量存储实例
- 对外提供一个静态公有方法获取实例
使用场景
- 需要频繁的创建和销毁对象;
- 创建对象时耗时过多或耗费资源过多(重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)
实现方式
1. 饿汉式 - 静态常量
1 | public class Singleton { |
实现方式:
- 构造器私有化,类外部无法使用 new 对象
- 类内部创建一个静态常量的实例对象
- 提供一个公有的静态方法,用来获取唯一的实例对象
优缺点:
优点:简单,在类装载时完成了实例的创建,避免线程同步,线程安全
缺点:不能实现 lazy loading,浪费内存
2. 饿汉式 - 静态代码块
1 | public class Singleton { |
与静态常量的实现方式类似,只是将类的实例化放在了静态代码块中,也是在类装载时实现的,优缺点同上。
3. 懒汉式 - 线程不安全
1 | public class Singleton { |
优缺点:
优点:起到了 Lazy Loading 的效果,但是只能在单线程下使用。
缺点:在多线程下,一个线程进入了 if (singleton == null)
判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式
在实际开发中,不要使用这种方式
4. 懒汉式 - 线程安全 - 方法加锁
1 | public class Singleton { |
优缺点:
优点:线程安全
缺点:每次执行 getInstance()
方法都需要加锁,效率较低
5. 懒汉式 - 线程安全 - 双重检查(推荐)
1 | public class Singleton { |
双重检查,保证了线程安全,volatile
关键字避免了指令重排序的影响,lazy loading 效率较高。
6. 静态内部类 - 推荐
1 | public class Singleton { |
通过类的加载机制保证该类只有一个实例对象。
Singleton 加载时不会实例化对象,需要实例化时调用 getInstance()
方法,加载 SingletonInstance
类,完成外部类的实例化。JVM 保证了线程安全。
避免了线程不安全,利用静态内部类特点实现延迟加载,效率较高。
7. 枚举 - 推荐
1 | public enum EnumSingleton { |
不仅能避免多线程同步问题,而且还能防止反序列化重新创建 新的对象。
- 本文作者: Kelly Liu
- 本文链接: http://tiantianliu2018.github.io/2021/07/25/设计模式-单例模式/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!