单例模式详解

  1. 定义

单例模式指的是一个类,在全局范围内(整个系统中)有且只能有一个实例存在。即该类本身负责提供一种访问其唯一对象的方式,不对外提供公共的构造函数(禁用默认公共构造函数),对于该类的实例化由它自己在类的内部进行维护!

  1. 优缺点

    • 优点

      1. 最大程度的减少了对象的创建和销毁的次数,从而降低的垃圾回收的次数

      2. 节约了系统资源,尤其是内存资源

    • 缺点

      1. 不能继承,不能被外部实例化

      2. 类干预了外部类的使用(外部实用类不能随意实例化),而不再仅仅专注于内部的逻辑(与单一职责模式有矛盾)

  1. 使用场景

    • 有频繁的实例化后又销毁的情况,适合考虑使用单例模式,如记录日志的log对象

    • 创建对象需要消耗过多的系统资源,但又经常用到的资源,如数据库连接

  2. 框架中的应用

    1. spring框架中的Bean默认都是单例的

  1. 实现方式

    单例模式有多种实现方式,要考虑到多线程下的安全性,其每种实现方式如下所示:

    1. 懒加载(线程不安全)

      public class SingletonPattern {
          private static SingletonPattern instance;
      ​
          private SingletonPattern(){}
      ​
          public static SingletonPattern getInstance(){
              if (instance == null){
                  instance = new SingletonPattern();
              }
              return instance;
          }
      }

      以上方式,如果存在多个线程同时访问getInstance()时,由于没有锁机制,会导致实例化出现两个实例的情况,因此,在多线程环境下时不安全的。

    2. 懒加载(线程安全)

      public class SingletonPattern {
          private static SingletonPattern instance;
      ​
          private SingletonPattern(){}
      ​
          public static synchronized SingletonPattern getInstance(){
              if (instance == null){
                  instance = new SingletonPattern();
              }
              return instance;
          }
      }

      如上代码所示,在getInstance()方法上添加了同步锁。但是该方法虽然解决了线程安全的问题,但却也带来了另外的一个问题,就是每次获取对象时,都要先获取锁,并发性能很差,还需要继续优化!

    3. 双重校验(线程安全)

      public class SingletonPattern {
          private static SingletonPattern instance;
      ​
          private SingletonPattern(){}
      ​
          public static SingletonPattern getInstance(){
              if (instance == null){
                  synchronized (SingletonPattern.class){
                      instance = new SingletonPattern();
                  }
              }
              return instance;
          }
      }

      该方法将方法上的锁去掉了,避免了每次调用该方法都要获取锁的操作,从而提升了并发性能,同时在方法内部使用锁,进而解决了并发的问题,从而解决了上面并发安全+性能低效的问题,是个不错的实现单例的方式。

    1. 饿汉式(线程安全)

      public class SingletonPattern {
          private static SingletonPattern instance = new SingletonPattern();
      ​
          private SingletonPattern(){}
      ​
          public static SingletonPattern getInstance(){
              
              return instance;
          }
      }

      该方式虽然简单也安全,但是会造成再不需要实例时,产生垃圾对象,造成资源狼粪,因此,一般不使用。

    1. 内部静态类(线程安全)

      public class SingletonPattern {
          private static class SingletonPatternHolder{
              public static SingletonPattern instance = new SingletonPattern();
          }
      ​
          private SingletonPattern(){}
      ​
          public static SingletonPattern getInstance(){
      ​
              return SingletonPatternHolder.instance;
          }
      }

      这种方式可以达到跟双重校验锁一样的效果,但只适用于静态域的情况,双重校验锁可在实例域需要延迟初始化时使用

    1. 枚举(线程安全)

      public enum SingletonPattern {
          INSTANCE;
      ​
          public static SingletonPattern getInstance(){
              return INSTANCE;
          }
      }

      这是实现单例模式的最佳方法,更加简洁,自动支持序列化,杜绝防止多次实例化,非常高效!(强烈推荐使用)

  1. 引用

欢迎大家在评论区进行讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

面朝大海,春不暖,花不开

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值