美文网首页
单例模式

单例模式

作者: AdamSun19 | 来源:发表于2021-10-31 19:29 被阅读0次

    定义

    应用场景

    实现

    饿汉式

    线程安全,所有对象类在加载时实例化,如果系统中单例对象比较多,不论是否在使用,都占着空间,造成内存浪费

    demo1

    public class Singleton {
      private static final Singleton instance = new Singleton();
      // 私有化构造方法,避免直接创建对象
      private Singleton() {}
      // 提供获取对象的方法
      public static Singleton getInstance() {
        return instance;  
      }
    }
    

    demo2

    这里使用静态代码块的机制实现

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

    懒汉式

    懒汉式,在使用时创建对象,避免了饿汉式单例模式造成的内存浪费

    demo1

    这个例子存在线程安全问题,例:threadA在getInstance()时,instance为空,而这时,threadB也调用getInstance()方法,instance也为空,threadA和threadB分别创建了一个对象实例

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

    demo2

    解决懒汉式demo1中的线程安全问题,这种方式效率较低,同一时刻仅有一个线程执行该方法

    public class LazySingleton {
      private static LazySingleton instance;
      private LazySingleton() {}
      // 直接同步整个方法,简单粗暴
      public synchronized static LazySingleton getInstance() {
        if (instance == null) {
          instance = new LazySingleton();
        }
        return instance;
      }
    }
    

    demo3 双检锁

    public class LazySingleton {
      private static LazySingleton instance;
      private LazySingleton() {}
      // 直接同步整个方法,简单粗暴
      public static LazySingleton getInstance() {
        if (instance == null) {
          synchronized(LazySingleton.class) {
            if (instance == null) {
              instance = new LazySingleton();
            }
          }
        }
        return instance;
      }
    }
    

    静态内部类

    线程安全,懒汉式,避免了内存浪费和synchronized性能问题

    public class LazyStaticInnerClassSingleton {
      private LazyStaticInnerClassSingleton() {}
      
      private static LazyStaticInnerClassSingleton getInstance() {
        return LazyHolder.INSTANCE;
      }
      private static class LazyHolder {
        private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton ();
      }
    }
    

    枚举

    public enum EnumSingleton {
      INSTANCE;
      public static EnumSingleton getInstance() {
        return INSTANCE;
      }
    }
    

    拓展

    反射破坏单例

    在实现单例类的时候,我们私有化了构造方法,这样理论上我们就没有办法通过构造方法直接创建一个新的对象。private 修饰的构造方法仅能在类内调用。
    不过Java提供了强大的工具 - 反射,通过反射,我们可以直接获取到对象内部的属性、方法等,包括私有属性、方法。

    try {
      Class<?> clazz = LazyInstance.class;
      // 获取类的构造方法
      Constructor c = clazz.getDeclaredConstructor(null);
      // 强制访问  
      c.setAccessible(true);
      // 通过反射创建两个对象
      Object instance1 = c.newInstance();
      Object instance2 = c.newInstance();
      System.out.println(instance1 == instance2);//false
    } catch(Exception e) {
      e.printStackTrace();
    }
    

    解决反射破坏单例的问题

    public class LazyStaticInnerClassSingleton {
      private LazyStaticInnerClassSingleton() {
        if (LazyHolder.INSTANCE != null) {
          throw new RuntimeException("Cann't create multiple instance.");
        }
      }
      
      private static LazyStaticInnerClassSingleton getInstance() {
        return LazyHolder.INSTANCE;
      }
      private static class LazyHolder {
        private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton ();
      }
    }
    

    序列化破坏单例

    重写readResolve()方法

    相关文章

      网友评论

          本文标题:单例模式

          本文链接:https://www.haomeiwen.com/subject/uzooaltx.html