# gupaoedu-vip-pattern-singleton **Repository Path**: lichaoying/gupaoedu-vip-pattern-singleton ## Basic Information - **Project Name**: gupaoedu-vip-pattern-singleton - **Description**: java架构师-设计模式-单例模式 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-01-08 - **Last Updated**: 2022-01-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # java架构师-设计模式-单例模式 --- ## 单例模式:***保证独一无二*** spring 可参考 ApplictionContext,Calender --- # 应用场景 > 确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。单例模式是创建型模式。单例模式在现实生活中应用也非常广泛。 > 例如,国家主席、公司 CEO、部门经理等 。 > > 在 J2EE 标准中,ServletContext、ServletContextConfig等 > > 在 Spring 框架应用中 ApplicationContext; 数据库的连接池也都是单例形式。 # 单例模式 > 在整个运行环境过程中,一个类只产生一个唯一的实例对象, ## 饿汉式单例 特点:它是在类加载的时候就立即初始化,并且创建单例对象 > 饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线 程还没出现以前就是实例化了,不可能存在访问安全问题。 > > **优点**:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。 > > **缺点**:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅 坑不拉屎 ## 懒汉式单例 特点:在外部需要使用的时候才进行实例化 ### 1.简单懒汉 * 静态块,公共内存区域 ### 2.懒汉(volatile) * 为保证运行效率,实现双认证(jvm重排序有可能导致单例失效)LazyDoubleCheckSingleton ### 3.懒汉 (内部类) * 这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题 * 完美地屏蔽了这两个缺点,史上最牛B的单例模式的实现方式 * 如果没使用的话,内部类是不加载的 ## 注册式单例(枚举) > 注册式单例又称为登记式单例,就是将每一个实例都登记到某一个地方,使用唯一的标识获取实例。注册式单例有两种写法:一种为容器缓存,一种为枚举登记 ### 容器缓存 ContainerSingleton ```java public class ContainerSingleton { private ContainerSingleton(){} private static Map ioc = new ConcurrentHashMap(); public static Object getInstance(String className){ synchronized (ioc) { if (!ioc.containsKey(className)) { Object obj = null; try { obj = Class.forName(className).newInstance(); ioc.put(className, obj); } catch (Exception e) { e.printStackTrace(); } return obj; } else { return ioc.get(className); } } } } ``` ### 枚举登记 EnumSingleton ```java public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance(){ return INSTANCE; } } ``` ## ThreadLocal 线程单例 > ThreadLocal 不能保证其创建的对象是全局唯一,但是能保证在单个线程中是唯一的,天生的线程安全 那么 ThreadLocal 是如果实现这样的效果的呢? > 我们知道上面的单例模式为了达到线程安全的目的,给方法上锁,以时间换空间。ThreadLocal 将所有的对象全部放在 > ThreadLocalMap 中,为每个线程都提供一个对象,实际上是以空间换时间来实现线程间隔离的 。 ## 单例的所有实现方式有如下特点: 1. 私有对象属性 2. 私有构造函数 3. 都会有一个静态的方法用于获取唯一实例对象 ## 破坏单例 不进行特殊处理的话,反射与反序列化都会存在获取不同对象的漏洞 ### 反射: 在私有构造函数中,增加对象不为空的判断,如果对象不为空还调用了私有构造函数,则抛异常表示有人想异常进行获取,见StaticInnerClass.java类; ### 反序列化: > 有时候需要将对象序列化然后写入到磁盘,下次使用时 再从磁盘中读取到对象,反序列化转化为内存对象。反序列化后的对象会重新分配内存,即重新创建 增加private Object readResolve() {return singleton;} 方法,见HungrySingleton.java类;