Java - 单例模式

379 阅读2分钟
import java.util.HashMap;
import java.util.Map;

/**
 * @author The one
 * @date 2021-09-06 09:11
 * @describe 单例模式 - 创造型
 * @email 625805189@qq.com
 * @remark 1.构造方法不是公开的,一般是private
 *         2.通过一个静态的方法或者枚举返回单例对象
 *         3.注意多线程场景
 *         4.单例类对象在反序列化时不会重新创建对象
 */
public class SingletonPattern {

    /**
     * 懒汉式
     * TODO 开销比较大,希望用到时才创建就要考虑延迟实例化 Singleton的初始化需要某些外部资源(比如网络或存储设备)
     */
    static class Singleton1{

        /**
         * 私有的构造方法
         */
        private Singleton1(){}

        /**
         * 私有的静态变量
         * static修饰的变量以s开头命名
         * [volatile] JDK 1.5 -> 防止指令重排
         */
        private volatile static Singleton1 sInstance = null;

        /**
         * 暴露一个公开的获取单列的方法
         */
        public static  Singleton1 getInstance(){
            // DCL 双重校验
            // 第一层校验
            if(null == sInstance){
                synchronized (Singleton1.class){
                    // 第二层校验
                    if(null == sInstance){
                        sInstance = new Singleton1();
                        // 上面这句代码会执行以下指令
                        // 1. sInstance实例分配对象
                        // 2. 调用Singleton1的构造方法,初始化成员变量
                        // 3. Singleton1对象赋值给sInstance
                        // JDK -> 指令重排,三个步骤可能乱序,会导致双重校验失效
                    }
                }
            }
            return sInstance;
        }
    }

    /**
     * 恶汉模式
     *
     * TODO 应用程序总是创建并使用单例实例或在创建和运行时开销不大
     */
    static class Singleton2{

        private Singleton2(){}

        /**
         * 类加载的时候单例就已经被加载了
         */
        private static Singleton2 sInstance = new Singleton2();

        public static Singleton2 getInstance(){
            return sInstance;
        }

    }

    /**
     * 静态类部类
     */
    static class Singleton3{


        private static class Holder{

            /**
             * 第一次虚拟机加载Singleton3对象时,sInstance 并不会被初始化
             */
           private static final Singleton3 sInstance = new Singleton3();

        }

        /**
         * 调用此方法时, Holder.sInstance 才会被初始化。做到了延迟加载。
         */
        public static Singleton3 getInstance(){
            return Holder.sInstance;
        }

    }

    /**
     * 枚举默认是线程安全的,任何情况下都是单例的
     */
    static class Singleton4{

        private Singleton4(){}

         enum SingleEnum{
            INSTANCE;

            private Singleton4 single;

            private SingleEnum (){
                single = new Singleton4();
            }

            public Singleton4 getSingle(){
                return single;
            }

        }

        public static Singleton4 getInstance(){
            return SingleEnum.INSTANCE.getSingle();
        }


    }

    /**
     * 单例管理器
     */
    static class SingletonManager{

        private final static Map<String,Object> OBJ_MAP = new HashMap<>();

        public static void registerService(String key,Object instance){
            if(!OBJ_MAP.containsKey(key)){
                OBJ_MAP.put(key,instance);
            }
        }

        public static Object getService(String key){
            return  OBJ_MAP.get(key);
        }

    }

}