Singleton

作者: 93张先生 | 来源:发表于2020-09-24 09:36 被阅读0次

    单例模式

    单例模式允许一个应用程序在每一个 JVM 实例中有且只有一个类的实例对象。

    特征

    • 一个JVM 实例内只有一个类的实例对象。

    饿汉模式

    public class EagerSingleton {
        private static final EagerSingleton instance = new EagerSingleton();
     
        // private constructor
        private EagerSingleton() {
        }
     
        public static EagerSingleton getInstance() {
            return instance;
        }
    }
    

    懒汉模式

    public class LazySingleton {
        private static volatile LazySingleton instance = null;
     
        // private constructor
        private LazySingleton() {
        }
     
        public static LazySingleton getInstance() {
            if (instance == null) {
                synchronized (LazySingleton.class) {
                    // Double check
                    if (instance == null) {
                        instance = new LazySingleton();
                    }
                }
            }
            return instance;
        }
    }
    
    双重懒加载

    使用volatile关键字的目的不是保证可见性(synchronized已经保证了可见性),而是为了保证顺序性。具体来说,INSTANCE = new Singleton()不是原子操作,实际上被拆分为了三步:1) 分配内存;2) 初始化对象;3) 将INSTANCE指向分配的对象内存地址。 如果没有volatile,可能会发生指令重排,使得INSTANCE先指向内存地址,而对象尚未初始化,其它线程直接使用INSTANCE引用进行对象操作时出错。

    双重空检查:防止两个线程,实例化两个对象。一个线程T1 读到对象为空,另一个线程T2读到对象也为空,T1 加锁实例化,T2 加锁实例化。这样就是两个实例了。

    静态代码块

    public class StaticBlockSingleton {
        private static final StaticBlockSingleton INSTANCE;
     
        static {
            try {
                INSTANCE = new StaticBlockSingleton();
            } catch (Exception e) {
                throw new RuntimeException("Uffff, i was not expecting this!", e);
            }
        }
     
        public static StaticBlockSingleton getInstance() {
            return INSTANCE;
        }
     
        private StaticBlockSingleton() {
            // ...
        }
    }
    

    静态内部类

    推荐

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

    枚举

    public enum EnumSingleton {
        INSTANCE;
        public void someMethod(String param) {
            // some class member
        }
    
      // 该方法非必须,只是为了保证与其它方案一样使用静态方法得到实例
      public static EnumSingleton getInstance() {
        return INSTANCE;
      }
    }
    

    序列化&反序列化问题

    public class DemoSingleton implements Serializable {
        private static final long serialVersionUID = 1L;
     
        private DemoSingleton() {
            // private constructor
        }
     
        private static class DemoSingletonHolder {
            public static final DemoSingleton INSTANCE = new DemoSingleton();
        }
     
        public static DemoSingleton getInstance() {
            return DemoSingletonHolder.INSTANCE;
        }
     
        protected Object readResolve() {
            return getInstance();
        }
    }
    

    场景

    • java.lang.Runtime.getRuntime();
    public class Runtime {
        private static Runtime currentRuntime = new Runtime();
        public static Runtime getRuntime() {
            return currentRuntime;
        }
    }
    
    • MyBatis 中的 VFS (Virtual File System) 实例
    public abstract class VFS {
       private static class VFSHolder {
        // 单例模式, 全局唯一 VFS 对象
        static final VFS INSTANCE = createVFS();
    
        static VFS createVFS() {
          // Try the user implementations first, then the built-ins
          // 优先使用用户自义的 VFS 现, 如采没自定义 VFS 实现,则使用 MyBatis 提供的 VFS 实现
          List<Class<? extends VFS>> impls = new ArrayList<>();
          impls.addAll(USER_IMPLEMENTATIONS);
          impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));
    
          // Try each implementation class until a valid one is found
          // 造历 impls 集合,依次实例化 VFS 对象并检测 VFS 对象是否有效,一旦得到有效的 VFS 对象,则结束循环
          VFS vfs = null;
          for (int i = 0; vfs == null || !vfs.isValid(); i++) {
            Class<? extends VFS> impl = impls.get(i);
              // 通过类的构造方法创建VFS实例
              vfs = impl.getDeclaredConstructor().newInstance();
              if (!vfs.isValid()) {
                if (log.isDebugEnabled()) {
                  log.debug("VFS implementation " + impl.getName() +
                      " is not valid in this environment.");
                }
              }
          return vfs;
        }
      }
    
      /**
       * Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the
       * current environment, then this method returns null.
       */
      public static VFS getInstance() {
        return VFSHolder.INSTANCE;
      }
    }
    

    VFS 表示虚件系统 Virtual File System 来查找指定路径下的资源。资源比如: jar 或者 class 文件

    相关文章

      网友评论

        本文标题:Singleton

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