第二章面试题2:实现单例模式

什么是单例模式

Singleton:保证一个类只有一个实例,且提供一个访问它的全局访问点

为什么需要单例模式

  1. 有一些类只需要使用一个实例,如工具箱等
  2. 需要实现对唯一实例的受控访问

怎么实现单例模式

要求:

  1. 判断对象是否被实例化,若实例化了则直接使用实例
  2. 是否实例化应该由该类自己判断,不需要客户判断,不允许其他类实例该类,则需要构造方法私有化
  3. 客户通过该类的public方法使用实例

代码实现

单线程下

//懒汉式——需要时再创建(第一次使用时实例化)
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是否为空,两个判断全部为真,创建两个实例,线程不安全
饿汉式:一开始就创建好,后续部分不进行创建,线程安全

比较项目 懒汉式 饿汉式
含义 第一次使用时创建 类初始化时创建
优势与劣势 当不需要时不创建,节约系统资源,线程不安全 线程安全,浪费系统资源
多线程情况 不安全 安全
如何改进懒汉式和饿汉式
  1. 改进懒汉式

    //在第一次使用时创建,且针对实例是否为空加锁
    public class Singleton{
         private static Singleton instance;
    
         private Singleton{};
         //效果同直接在getInstance方法上加synchronized标签相同
         public static Singleton getInstance(){
             synchronized{
               if(instance == null){
                  instance = new Singleton();
               }
             }
             return instance;
         }
    }
    //缺点——当一个线程进入该方法后,其他线程都需要等待,性能上有损耗

    继续改进

    //双重校验锁——只有当实例为空的时候才进入同步代码块
    public class Singleton{
       private static Singleton instance;
    
       private Singleton{};
    
       public static Singleton getInstance(){
           if(instance == null){
               synchronized(this){
                  if(instance == null){
                      instance = new Singleton();
                  }
               }
           }
       }
    }
    //为什么要判断instance两次:
    //AB线程同时判断instance为空,A进入同步代码块,获得实例,此时instance为具体引用,B进入同步代码块,若不判断instance是否为空,则会重新创建一个新的实例。
  2. 改进饿汉式
//使用内部类
public class Singleton{

   private class InnerSingleton{
      private static Singleton instance = new Singleton();
   }

   public static Singleton getInstance(){

       return InnerSingleton.instance;
   }
}
//使用枚举类
public Enum Singleton{
   INSTANCE;
   public void otherMethod(){};

}

//使用方法
public static void Main(String[] args){
   Singleton.INSTANCE.otherMethod();
}

猜你喜欢

转载自blog.csdn.net/athitera/article/details/80256793
今日推荐