创建型模式的主要特点是:将对象的创建与使用分离。以此降低系统的耦合度

在很多系统设计中要求某些类的实例全局只能有一份,以此保证数据一致性,这就是所谓的单例模式。
单例模式的定义为:一个类只能有一个实例,且该类能够自行创建出这个实例并向外部提供的模式。

优点:

  1. 内存中只存储一份实例,减少了内存开销
  2. 避免资源的多重占用
  3. 单例类有全局唯一的访问入口,严格控制外部的访问

缺点:

  1. 单例模式一般没有接口,扩展困难

应用场景

  1. 需要频繁创建或者销毁的类,可以降低内存压力,减少GC
  2. 创建实例时占用资源过多,或者耗时较长,且经常使用

设计重点

  1. 私有化构造器
  2. 线程安全
  3. 双重检查
  4. 延迟加载
  5. 序列化和反序列化安全
  6. 反射

懒汉式单例

存在问题:每次访问都需要进行同步,耗费性能

  1. public class LazySingleton {
  2. // volatile 只保证可见性和有序性,不保证原子性
  3. private static volatile LazySingleton instance = null;
  4. // 私有化构造器
  5. private LazySingleton(){
  6. }
  7. // 通过加锁的方式避免了重复创建实例
  8. public static synchronized LazySingleton getInstance() {
  9. if (instance == null){
  10. /**
  11. * 步骤:
  12. * 1. 分配对象空间
  13. * 2. 初始化对象
  14. * 3. instance指向被分配好的内存地址
  15. *
  16. * 步骤2,3是可以发生交换的,这也是指令重排序问题,而volatile则很好的解决了这一问题
  17. */
  18. instance = new LazySingleton();
  19. }
  20. return instance;
  21. }
  22. }

双重检查

优点:仅在第一次获取实例的时候进行同步

  1. public class LazySingleton {
  2. // 这里不再需要volatile去保证有序性了,因为下面的双重检查可以确保实例只会有一份
  3. private static LazySingleton instance = null;
  4. // 私有化构造器
  5. private LazySingleton(){
  6. }
  7. // 双重检查
  8. public static LazySingleton getInstance() {
  9. if (instance == null){
  10. synchronized (LazySingleton.class){
  11. if (instance == null){
  12. instance = new LazySingleton();
  13. }
  14. }
  15. }
  16. return instance;
  17. }
  18. }

静态内部类

优点:初始化Singleton类的时候并不会初始化 INSTANCE ,只有首次调用的时候才会进行初始化,这样即保证了线程安全,也可以保证Singleton实例的唯一

  1. class Singleton{
  2. // 静态内部类
  3. private static class InnerClass{
  4. private static final Singleton INSTANCE = new Singleton();
  5. }
  6. public static Singleton getInstance() {
  7. return InnerClass.INSTANCE;
  8. }
  9. }

枚举

推荐使用的一种方式,因为基于枚举的特点,它无法在任何时候被修改,如果测试就可以发现其他方式都可以被反射修改实例,但是枚举是无法被修改的。

  1. enum Singleton{
  2. INSTANCE;
  3. }

饿汉式单例

特点:在类加载的时候就已经创建好了对象,直接调用接口,先天避免了线程安全问题

  1. class HungrySingleton{
  2. private static final HungrySingleton instance = new HungrySingleton();
  3. // 构造器私有化
  4. private HungrySingleton(){}
  5. public static HungrySingleton getInstance() {
  6. return instance;
  7. }
  8. }