手写单例模式

单例模式

  1. 原则:保证一个类只会有一个实例,全局唯一。

  2. 特征:

    • 构造函数私有化(确保不能在该类的外部通过构造函数来创建对象)
    • 提供获取单例的公有静态方法;
    • 使用static修饰单例的引用变量;
  3. 实现模式:

    • 饿汉模式:在类加载到内存中时完成实例化,缺点就是可能会浪费内存空间,如果该类从始至终都没有被使用的话;
    • 懒汉模式:单例被延迟实例化,只有在尝试获取该实例时才会完成实例化;缺点就是可能会带来线程安全问题;
  4. 饿汉式代码实现;

    • 由于创建时完成了实例化所以不会有线程安全问题;
      public class HungryMode {
          private HungryMode(){};   // 构造函数私有化
          private static HungryMode singleton = new HungryMode();   // 在加载类的过程中完成单例的创建
          public static HungryMode getSingleton(){        // 提供获取单例的公有静态方法
              return singleton;
          }
      }
      
  5. 懒汉式代码实现(线程不安全式)

    • 在多线程场景下,这中写法是线程不安全的,一个线程执行了if(singleton == null) 语句,结果为true,但还没有来得及继续往下执行以创建实例,切换到了另一个线程又执行了这个判断,也会为true继续执行以创建实例,这样就会创建两个实例,违反了单一实例原则,代码如下:
    • public class LazyMode {
          private LazyMode(){};                    // 构造函数私有化
          private static LazyMode singleton;       // 延迟加载
          public static LazyMode getInstance(){    // 公有静态方法提供单例
              if(singleton == null){
                  singleton = new LazyMode();
              }
              return singleton;
          }
      }
      
  6. 懒汉式代码实现(双重校验锁-线程安全)

    • 加锁操作只对实例化那一部分代码进行,而不是对整个getSingleton()方法进行加锁,从而避免了单例已经存在之后的加锁操作;也就是即使单例已经存在,但是当一个线程进入该方法后,其他试图进入该方法的线程都必须等待,这会让线程阻塞更长时间;

    • volatile防止指令重排,主要由于 singleton = new LazyMode(); 不是原子操作,此行代码分为有以下几步执行:

      • 给实例分配内存;
      • 初始化实例;
      • singleton 指向分配的内存地址;

      注意 由于指令重排可能导致执行顺序变为1->3->2,在多线程环境下,例如线程1先执行了1和3,然后切换到线程2,线程2调用getSingleton()后发现,singleton不为空,然后返回了一个未被初始化的单例;

    • 双重校验指的是两个 if(singleton == null),第一次校验是用于判断单例是否已存在; 第二次校验则是,如果当前单例未创建,然后两个线程都执行了第一个if语句并进入了语句块内,虽然语句块内会有加锁操作,但是两个线程也都是会执行实例的创建,只是先后而已,这就会创建两个实例;

    • 代码实现:

      public class LazyMode {
          private static volatile LazyMode singleton;   
          private LazyMode(){};
          public static LazyMode getSingleton(){
              if(singleton == null){               
                  synchronized (LazyMode.class){        // synchronized 修饰代码块
                      if(singleton == null){       
                          singleton = new LazyMode();
                      }
                  }
              }
              return singleton;
          }
      }
      

参考

  1. 参考一
  2. 参考二
  3. 参考三
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值