zoukankan      html  css  js  c++  java
  • 设计模式-单例模式

    一、定义

     确保某个类只有一个实例,并向整个系统提供出这个实例。

    二、类型

     创建型

    三、适用场景

     想确保任何情况下都只有一个实例

    四、优点

    • 内存只有一个实例,节省内存。
    • 避免对资源多重占用。
    • 在系统设置全局访问点,优化和共享资源访问。

    五、缺点

    •  一般没有接口,扩展困难。
    • 与单一职责有冲突。

    六、类图

     过于简单,略

    七、代码实现

    1、懒汉式:

    package com.wms.createtype.singleton;
    
    public class LazySingleton {
        private static LazySingleton lazySingleton = null;
        private LazySingleton() {}
        public static LazySingleton getInstance() {
            synchronized (LazySingleton.class) {
                if (lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
            return lazySingleton;
        }
    }

     2、双重检查式:

    package com.wms.createtype.singleton;
    
    public class DoubleCheckSingleton {
        // volatile 禁止指令重排
        private volatile static DoubleCheckSingleton doubleCheckSingleton = null;
        private DoubleCheckSingleton() {}
        public static DoubleCheckSingleton getInstance() {
            if (doubleCheckSingleton == null) {
                synchronized (DoubleCheckSingleton.class) {
                    if (doubleCheckSingleton == null) {
                        // 1、分配内存给对象
                        // 2、初始化对象
                        // 3、赋值给doubleCheckSingleton
                        // jvm的指令重排可能会使得2和3这两步顺序不确定
                        // 当执行顺序是1->3->2的时候,就会出现问题,此时doubleCheckSingleton不为空,别的线程来获取这个单例对象
                        // 时就可能拿到还没初始化的这个对象,此时如果别的线程直接使用,就会出错。因此加上volatile禁止jvm指令重排
                        doubleCheckSingleton = new DoubleCheckSingleton();
                    }
                }
            }
            return doubleCheckSingleton;
        }
    }

     3、饿汉式:

    package com.wms.createtype.singleton;
    
    public class HungarySingleton {
        private static HungarySingleton hungarySingleton = new HungarySingleton();
        private HungarySingleton() {}
        public static HungarySingleton getInstance() {
            return hungarySingleton;
        }
    }

    4、静态内部内:

    package com.wms.createtype.singleton;
    
    public class StaticInnerClassSingleton {
        private StaticInnerClassSingleton() {}
    
        public static StaticInnerClassSingleton getInstance() {
            return InnerClass.staticInnerClassSingleton;
        }
        private static class InnerClass {
            private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
        }
    }

    5、枚举单例

    package com.wms.createtype.singleton;
    
    public enum EnumSingleton {
        INSTANCE;
        
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

     八、破坏单例

    1、反序列化破坏单例

    测试函数:

    package com.wms.createtype.singleton;
    
    import java.io.*;
    
    public class TestDesignParttern {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            HungarySingleton hungarySingleton = HungarySingleton.getInstance();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("singletion"));
            objectOutputStream.writeObject(hungarySingleton);
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("singletion"));
            HungarySingleton hungarySingleton01 = (HungarySingleton) objectInputStream.readObject();
            
            System.out.println(hungarySingleton == hungarySingleton01);  // false
        }
    }

    修改单例类:

    package com.wms.createtype.singleton;
    
    import java.io.Serializable;
    
    public class HungarySingleton implements Serializable {
        private static HungarySingleton hungarySingleton = new HungarySingleton();
        private HungarySingleton() {}
        public static HungarySingleton getInstance() {
            return hungarySingleton;
        }
    
        // 加上该方法在反序列化的时候返回已存在的单例对象
        public Object readResolve() {
            return hungarySingleton;
        }
    }

     防御方式:单例模式中增加反序列化方法,该方法隐式调用。

    2、反射破坏单例

    网上有些通过构造方法防御:

    package com.wms.createtype.singleton;
    
    import java.io.Serializable;
    
    public class HungarySingleton implements Serializable {
        private static HungarySingleton hungarySingleton = new HungarySingleton();
        private HungarySingleton() {
            if (hungarySingleton != null) {
                throw new RuntimeException("单例模式不允许调用构造方法实例化");
            }
        }
        public static HungarySingleton getInstance() {
            return hungarySingleton;
        }
    
        // 加上该方法在反序列化的时候返回已存在的单例对象
        public Object readResolve() {
            return hungarySingleton;
        }
    }

    破坏方式:

    package com.wms.createtype.singleton;
    
    import java.io.Serializable;
    
    public class HungarySingleton implements Serializable {
        private static final HungarySingleton hungarySingleton = new HungarySingleton();
        private HungarySingleton() {
            if (hungarySingleton != null) {
                throw new RuntimeException("单例模式不允许调用构造方法实例化");
            }
        }
        public static HungarySingleton getInstance() {
            return hungarySingleton;
        }
    
        // 加上该方法在反序列化的时候返回已存在的单例对象
        public Object readResolve() {
            return hungarySingleton;
        }
    }
    public class StaticInnerClassSingleton {
        private StaticInnerClassSingleton() {
            if (InnerClass.staticInnerClassSingleton != null) {
                throw new RuntimeException("单例模式不允许调用构造方法实例化");
            }
        }
    
        public static StaticInnerClassSingleton getInstance() {
            return InnerClass.staticInnerClassSingleton;
        }
        private static class InnerClass {
            private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
        }
    }

    防御方式:饿汉式和静态内部类,增加final修饰,可防止反射攻击,其他都无法防御。

    3、防御任何破坏单例的方式:Effective Java推荐尽可能地使用枚举来实现单例

  • 相关阅读:
    应用服务器性能优化总结
    Web性能优化:图片优化
    图片优化
    浏览器端的九种缓存机制介绍
    MySQL 与 MongoDB的操作对比
    js类型判别大合集
    节流函数和防抖函数的注意事项
    前端和后端交互的方式
    js中关于假值和空数组的总结
    LeetCode 367. 有效的完全平方数
  • 原文地址:https://www.cnblogs.com/wangmingshun/p/10203494.html
Copyright © 2011-2022 走看看