美文网首页
单例模式

单例模式

作者: yym_439 | 来源:发表于2019-02-20 16:43 被阅读0次

    定义

    保证一个类只有一个实例,并提供一个全局访问点

    优缺点

    • 只有一个实例,减少内存开销
    • 避免对资源的多重占用
    • 提供全局访问点,严格控制访问
      缺点:没有接口,拓展困难

    1、懒汉式

    • 线程安全,性能低
     private static LazySingleton lazySingleton = null;
        private LazySingleton(){
            if(lazySingleton != null){
                throw new RuntimeException("单例构造器禁止反射调用");
            }
        }
        public synchronized static LazySingleton getInstance(){
            if(lazySingleton == null){
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    

    2、双重检查机制

    • 线程安全,性能高
       private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;//volatile不允许2、3重排序
    
       private LazyDoubleCheckSingleton(){
    
       }
       public static LazyDoubleCheckSingleton getInstance(){
           if(lazyDoubleCheckSingleton == null){
               synchronized (LazyDoubleCheckSingleton.class){
                   if(lazyDoubleCheckSingleton == null){
                       lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                       //1.分配内存给这个对象
    //                  //3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
                       //2.初始化对象
    //                    intra-thread semantics
    //                    ---------------//3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
                   }
               }
           }
           return lazyDoubleCheckSingleton;
       }
    

    3、静态内部类单例

    • 也能解决2、3重排序问题
      //静态内部类有一个Class对象初始化锁
      private static class InnerClass{
            private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
        }
        public static StaticInnerClassSingleton getInstance(){
            return InnerClass.staticInnerClassSingleton;
        }
        private StaticInnerClassSingleton(){
            if(InnerClass.staticInnerClassSingleton != null){
                throw new RuntimeException("单例构造器禁止反射调用");
            }
        }
    

    4、饿汉式

    private final static HungrySingleton hungrySingleton;
    
        static{
            hungrySingleton = new HungrySingleton();
        }
        private HungrySingleton(){
            if(hungrySingleton != null){
                throw new RuntimeException("单例构造器禁止反射调用");
            }
        }
        public static HungrySingleton getInstance(){
            return hungrySingleton;
        }
    

    5、Enum枚举单例

    • 不存在序列化和发射问题
    public enum EnumInstance {
        INSTANCE;
    
        private Object data;
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
        public static EnumInstance getInstance(){
            return INSTANCE;
        }
    }
    

    6、容器类单例

    public class ContainerSingleton {
    
        private ContainerSingleton(){
    
        }
        private static Map<String,Object> singletonMap = new HashMap<String,Object>();
    
        public static void putInstance(String key,Object instance){
            if(StringUtils.isNotBlank(key) && instance != null){
                if(!singletonMap.containsKey(key)){
                    singletonMap.put(key,instance);
                }
            }
        }
    
        public static Object getInstance(String key){
            return singletonMap.get(key);
        }
    }
    

    序列化破坏单例模式

            HungrySingleton instance = HungrySingleton.getInstance();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
            oos.writeObject(instance);
    
            File file = new File("singleton_file");
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
    
            HungrySingleton newInstance = (HungrySingleton) ois.readObject();
           
            System.out.println(instance);
            System.out.println(newInstance);
            System.out.println(instance == newInstance); //false
    

    反射破坏单例模式

            Class objectClass = HungrySingleton.class;
            Constructor constructor = objectClass.getDeclaredConstructor();
            constructor.setAccessible(true); //获取构造函数权限
             HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
    
             HungrySingleton instance = HungrySingleton.getInstance();
    
             System.out.println(instance);
             System.out.println(newInstance);
             System.out.println(instance == newInstance); //false
    

    //解决方法

    public class HungrySingleton implements Serializable,Cloneable{
    
        private final static HungrySingleton hungrySingleton;
    
        static{
            hungrySingleton = new HungrySingleton();
        }
        private HungrySingleton(){
            //防止反射破坏单例
            if(hungrySingleton != null){
                throw new RuntimeException("单例构造器禁止反射调用");
            }
        }
        public static HungrySingleton getInstance(){
            return hungrySingleton;
        }
    
        //防止序列化破坏对象
        private Object readResolve(){
            return hungrySingleton;
        }
    }
    

    相关文章

      网友评论

          本文标题:单例模式

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