单例模式

单例模式简单的讲就是保证一个类最多只有一个实例。

  • 懒汉单例:即用到的时候再进行实例化。

      public class SingleTon {
      
          private static SingleTon singleTon;
      
          private SingleTon() {
      
          }
      
          public static SingleTon getInstance() {
              if (singleTon == null) {
                  singleTon = new SingleTon();
              }
              return singleTon;
          }
      }
    

上述实现方式的缺陷是很明显的,即不是线程安全的。设想如下情况:线程1在运行到判断singleTon == null之后被切换到线程2,则线程2页会进行singleTon == null的判断,然后线程2创建了一个实例,然后切换回线程1,继续执行,还会创建一个实例。

  • 懒汉修改1

      public class SingleTon {
      
          private static SingleTon singleTon;
      
          private SingleTon() {
      
          }
      
          public static synchronized SingleTon getInstance() {
              if (singleTon == null) {
                  singleTon = new SingleTon();
              }
              return singleTon;
          }
      }
    

显然,线程安全问题被解决了,但是其实按照我们上面的分析,只有在第一次创建的时候才会出现线程安全问题,为此将整个代码段都加锁会导致每次调用的时候都是线程同步的,其他线程都是阻塞的,这样显然效率不是很高。

  • 双重校验

      public class SingleTon {
          
          private volatile static SingleTon singleTon;
          
          private SingleTon(){
              
          }
          
          public static SingleTon getInstance(){
              if(singleTon == null){
                  synchronized(SingleTon.class){
                      if(singleTon == null){
                          singleTon = new SingleTon();
                      }
                  }
              }
              return singleTon;
          }
      }
    

这样就OK了,根据前面的分析,在有可能出现问题的部分加上锁,这样一来不仅能保证线程安全,还能保证效率。

  • 静态内部类
    public class SingleTon {

          private static class SingleTonHolder{
              private static final SingleTon singleTon = new SingleTon();
          }
      
          private SingleTon() {
      
          }
      
          public static SingleTon getInstance() {
              return SingleTonHolder.singleTon;
          }
      }
    
  • 饿汉单例:即类初始化时就实例化

      public class SingleTon {
          
          private static final SingleTon singleTon = new SingleTon();
      
          private SingleTon() {
      
          }
      
          public static SingleTon getInstance() {
              return singleTon;
          }
      }
    

这样子的话根本不存在线程安全问题了。不过问题就是,一上来就实例化,不管是否使用。

总结:建议使用双重校验或静态内部类的方式实现。

优点:对于一些需要不断的创建实例并销毁的情景,单例模式很大程度减少了内存的开支,由于只有一个实例且常驻内存, 减少了系统开销去不断的生成新实例,而且由于只有一个实例,还能避免对资源的多重访问。
缺点:有一个实例常驻内存,会有一定的系统开销,另外由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容