单例模式的复习

饿汉式

  1. 空间浪费
  2. 多线程安全
  3. 可能会被破坏


/**
 * 饿汉式,单例模式
 * 会存在空间的浪费(当还不需要单例时)
 * 多线程下是安全的
 */
class HungrySingle {
    private final static HungrySingle hs = new HungrySingle();

    private HungrySingle() {

    }

    public static HungrySingle getInstance() {
        return hs;
    }

}


懒汉式

  1. 多线程不安全
  2. 可能会被破坏


/**
 * 懒汉式单例设计模式
 * 多线程下不安全
 * 只有使用时,才会分配内存空间
 */
class LazySingle {

    private static LazySingle ls;

    private LazySingle() {

    }

    public static LazySingle getInstance() {
        if (ls != null) {
            ls = new LazySingle();
        }
        return ls;
    }


}

DCL懒汉式

  1. 多线程下是安全的
  2. 不会造成指令重排
  3. 双重锁


/**
 * DCL懒汉设计模式
 * 这个可能会被破坏
 * 懒汉设计模式提升版
 * 多线程下是安全的
 * 没有指令重排的安全隐患
 * 为什么要使用volatile关键字,防止指令重排
 * 正常分配空间的步骤
 * 1.分配内存空间
 * 2.执行构造方法,初始化对象
 * 3.把这个对象指向这个空间
 * 如果发生了指令重排 132
 * 当这时另一个线程在指令重排3结束时2还未开始时访问了单例,虽然单例已经不为空,但是还没有完成初始化
 * 就会产生异常
 */
class LazySingleImpro {
    private volatile static LazySingleImpro ls;

    private LazySingleImpro() {

    }
    public static LazySingleImpro getInstance() {

        if (ls == null) {
            synchronized (LazySingleImpro.class){
                if(ls==null){
                    ls= new LazySingleImpro();
                }
            }
        }
        return ls;
    }


}

使用枚举创建单例

问题

不论是饿汉式还是懒汉式的单例设计模式
懒汉式的单例设计模式尽管使用了双重检查锁
但是依旧无法阻挡单例模式的破坏
使用反射和序列化就可以破环饿汉式和懒汉式的单例

使用反射破坏懒汉式的单例



import java.lang.reflect.Constructor;

/**
 * @ClassName: SingletonClient
 * @Author: 楠
 * @Description: TODO
 */
public class SingletonClient {//这里的懒汉式的单例,又重新写了一个所以名字和上面是不一样的
    public static void main(String[] args) throws Exception{
        System.out.println("使用双重检查锁,懒汉式创建单例");
        LazySingleton instence = LazySingleton.getInstence();
        LazySingleton instence1 = LazySingleton.getInstence();
        System.out.println(instence);
        System.out.println(instence1);
        System.out.println();
        System.out.println("使用反射破环单例");
        Class<?> clazz = Class.forName("singleton.LazySingleton");
        Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance();
        Object o1 = declaredConstructor.newInstance();
        System.out.println(o);
        System.out.println(o1);
        System.out.println("可以发现使用反射确实可以破环饿汉和懒汉式的单例");

        System.out.println();
        System.out.println("使用枚举创建单例");
        EnumSingleton instance = EnumSingleton.getInstance();
        EnumSingleton instance1 = EnumSingleton.getInstance();
        System.out.println(instance);
        System.out.println(instance1);

    }
}

使用枚举创建单例

枚举是不允许使用反射创建对象的,使用反射创建枚举对象是会抛出异常


/**
 * @ClassName: EnumSingleton
 * @Author: 楠
 * @Description: 使用枚举创建单例
 */
public class EnumSingleton {
    //私有化构造函数
    private EnumSingleton (){

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值