我想要学会设计模式之单例模式

166 阅读2分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战


什么是单例模式?

单例模式定义:保证一个类仅有一个实例,并提供访问此实例的全局访问点。

从类别上来看,单例模式属于创建类型的一种常用的[软件设计模式]。通过单例模式的方法创建的类在当前进程中只有一个[实例](根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)可以说是设计模式中最简单的一个了。


单例模式用途

如果一个类负责连接数据库的线程池、日志记录逻辑等等,此时需要单例模式来保证对象不被重复创建,以达到降低开销的目的。


懒汉式单例(线程安全)
public class Singleton {  
      private static Singleton instance;  
      private Singleton (){
      }
      public static synchronized Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
 }  
​
懒汉式单例(线程不安全)
public class Singleton {  
      private static Singleton instance;  
      private Singleton (){
      }   
      public static Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
 }  
 /**
 在用户第一次调用时初始化,虽然节约了资源,但第一次加载时需要实例化,反映稍慢一些,而且在多线程不能正常工作。
*/
饿汉式

public class Singleton {  
     private static Singleton instance = new Singleton();  
     private Singleton (){
     }
     public static Singleton getInstance() {  
     return instance;  
     }  
 }  
 
 /*
 
 √这种方式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。 这种方式基于类加载机制避免了多线程的同步问题,但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。
​
*/
双重锁
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;  
     }  
 }  
 /*
 这种写法在getSingleton方法中对singleton进行了两次判空,第一次是为了不必要的同步,第二次是在singleton等于null的情况下才创建实例。在这里用到了volatile关键字,*/
静态内部类(推荐)
public class Singleton { 
    private Singleton(){
    }
      public static Singleton getInstance(){  
        return SingletonHolder.sInstance;  
    }  
    private static class SingletonHolder {  
        private static final Singleton sInstance = new Singleton();  
    }  
} 
​
分析:第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder 并初始化sInstance ,这样不仅能确保线程安全也能保证Singleton类的唯一性,所以推荐使用静态内部类单例模式。