单例模式 Singleton

发布时间 2023-12-21 08:54:44作者: 梅丹隆

一、定义

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

二、使用场景

希望确保任何情况下只有一个实例

三、优缺点

1、优点

  • 在内存里只有一个实例,减少内存开销
  • 可以避免资源的多重占用
  • 设置全局的访问点,严格控制访问

2、缺点

  • 没有接口,扩展困难

四、代码实现

1、懒汉式

  • 在被客户端首次调用的时候才会创建唯一实例
  • 加入双重检查锁机制的懒汉模式能够确保线程安全
public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
    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;
    }
}

2、饿汉式

类被加载的时候就立即初始化并创建唯一实例

public class HungrySingleton {

    private final static HungrySingleton hungrySingleton;

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

3、枚举饿汉式

public class EnumStarvingSingleton {
    private EnumStarvingSingleton(){}
    
    private EnumStarvingSingleton getInstance() {
        return ContainerHolder.HOLDER.instance;
    }
    
    private enum ContainerHolder {
        HOLDER;
        private EnumStarvingSingleton instance;
        ContainerHolder() {
            instance = new EnumStarvingSingleton();
        }
    }
}

问题:枚举如何抵挡序列化和反序列化攻击?
线索:ObjectInputStream的readObject源码

4、源码地址

https://github.com/Meidanlong/all-in-one/tree/master/design/src/main/java/com/mdl/design/pattern/creational/singleton

五、单例的破坏

1、序列化/反序列化

2、克隆

  1. 不实现Clonable接口
  2. clone方法中返回同一对象

3、反射

  1. 私有构造器内对是否已经有单例对象进行判断,如果已存在单例对象则抛出异常
  2. 懒汉式无法绝对避免单例攻击

4、枚举单例

  • 不受序列化和反射影响
  • 无法通过反射创建枚举对象

5、容器单例

  • 通过Map维护容器,保证单例

6、ThreadLocal单例

  • threadLocal维护的对象是线程唯一的
  • 是“容器单例”的一种实现