【小威哥の设计模式系列-1】单例模式

319 阅读3分钟

0:前言

设计模式不论是对于何种编程语言都非常重要的一个设计思想,可以让你的代码更加简洁,重用性,可维护性,灵活性大大提升。
但是目前java里面的设计模式很多都过于臃肿繁复,并且非常过度设计,偏离了设计模式本身简洁易用封装好的原始出发点,非常不可取,这个系列我就将探讨这些设计模式并且给出使用场景和方法的建议。



1:单例模式的经典应用

  • spring的bean各种默认都为单例模式
  • servlet的application


2:何时应该使用单例

在java万物都为对象的基础之,其实我们每创造一个对象,如果一直保持着可达路径,那么对象就会很多占用很大的heap区内存,那么如果我们在使用一些特定功能的对象实例的时候,可以不需要每次都去new,可以只创造一个实例进行复用(或者在多线程并发问题的话可以使用我们之后将会介绍的池资源模式),那么可以极大节省new对象的开销和heap内存空间



3:单例模式的使用方法

1:饿汉模式--不管用不用,刚开始就给你构建了实例

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

问题:不管用不用都会在类装载的时候生成实例,拖慢装载速度,不符合lazyload的思想。不推荐使用。

2:懒汉模式--lazyload

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

问题:使用lazyload思想,但是会用多线程并发的问题,不允许推荐。

3:线程安全的懒汉模式

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

问题:可以保证多线程并发问题,但是每次获取实例都会synchronized,开销较大,不推荐。

4:双重校验线程安全的的懒汉模式

public class Singleton {  
      private volatile static Singleton instance;  
      private Singleton (){
      }   
      public static Singleton getInstance() {  
      if (instance== null) {  
          synchronized (Singleton.class) {  
          if (instance== null) {  
              instance= new Singleton();  
          }  
         }  
     }  
     return singleton;  
     }  
 }  

问题:可以保证多线程并发问题,也符合lazyload思想,但是因为volatile的一些诡异问题(在我的另一篇文章有介绍 : juejin.cn/post/684490…),在超级极端下会出现问题,稍稍推荐使用,但是最推荐的还是下面的第五种方式。

5:静态内部类方式--推荐使用的方式

public class Singleton {
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    private static class SingletonHolder {
        private static final ModeInnerClass INSTANCE = new ModeInnerClass();
    }
}

内部类实现方式, 因为jvm在加载类的时候只允许一个线程加载,所以在jvm层面就实现了同步,不用加syn关键字,强烈推荐使用。



4:总结

单例模式作为最简单也最接地气的的一种设计模式,为我们敲开了设计模式学习的大门,小小的模式却蕴含了面向对象编程以及并发,线程内存等的很多知识点,值得我们去好好学习和理解。