彻底玩转单例模式

单例模式

饿汉式

// 单例模式-饿汉式
// 缺点:在类加载时就new出了对象,可能造成浪费空间
public class Hungry {
    private final static Hungry eHanDemo = new Hungry();

    private Hungry(){
    }

    public static Hungry getInstance(){
        return eHanDemo;
    }
}

懒汉式

// 懒汉式:当需要用这个对象时,再进行创建
// 这样创建懒汉式存在问题:由于新建对象时不是原子操作,当多个线程同时需要创建对象,可能出现创建出多个对象。
public class LazyManDemo01 {

    private static LazyManDemo01 lazyManDemo01;

    private LazyManDemo01() {
    }

    public static LazyManDemo01 getInstance() {
        if (lazyManDemo01 == null) {
            lazyManDemo01 = new LazyManDemo01();
        }
        return lazyManDemo01;
    }
}

DCL懒汉式,防止多线程情况下创建出多个对象问题

// DCL懒汉式,可防止多线程情况下创建多个对象
// 问题,当通过反射方式镜像创建对象时,还是可以创建多个对象。
public class LazyManDemo02 {

    private volatile static LazyManDemo02 lazyManDemo02;

    private LazyManDemo02() {
    }

    // 双重检测锁模式的 懒汉式单例  DCL懒汉式
    public static LazyManDemo02 getInstance() {
        if (lazyManDemo02 == null) {
            synchronized (LazyManDemo02.class) {
                if (lazyManDemo02 == null) {
                    lazyManDemo02 = new LazyManDemo02();    // 不是原子操作
                    /**
                     * 1. 分配内存空间
                     * 2. 执行构造方法,初始化对象
                     * 3. 把这个对象指向这个空间
                     * 防止指令重排,用 volatile 修饰 lazyManDemo02
                     */
                }
            }
        }
        return lazyManDemo02;
    }

    // 反射!
    public static void main(String[] args) throws Exception {
        // LazyManDemo02 instance = LazyManDemo02.getInstance();

        Constructor<LazyManDemo02> declaredConstructor = LazyManDemo02.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyManDemo02 lazyManDemo02 = declaredConstructor.newInstance();
        LazyManDemo02 lazyManDemo022 = declaredConstructor.newInstance();

        System.out.println(lazyManDemo02);
        System.out.println(lazyManDemo022);

    }
}

设置一个flag变量,判断是否创建过对象,防止反射操作获取多个对象
但通过反射改变 flag 变量值,同样无法避免创建多个对象

// 设置一个flag变量,判断是否创建过对象,防止反射操作获取
// 问题,但通过反射也能改变 flag 的值,从而达到创建多个对象
public class LazyManDemo03 {

    private volatile static LazyManDemo03 lazyManDemo03;

    private static boolean flag = false;

    private LazyManDemo03() {
        synchronized (LazyManDemo03.class){
            if (flag == false){
                flag = true;
            }else {
                throw new RuntimeException("不要试图使用反射破坏");
            }
        }
    }

    // 双重检测锁模式的 懒汉式单例  DCL懒汉式
    public static LazyManDemo03 getInstance() {
        if (lazyManDemo03 == null) {
            synchronized (LazyManDemo03.class) {
                if (lazyManDemo03 == null) {
                    lazyManDemo03 = new LazyManDemo03();    // 不是原子操作
                }
            }
        }
        return lazyManDemo03;
    }
}

通过查看反射源码发现,枚举类不能通过反射获取在这里插入图片描述
枚举类单例

// enum 是一个什么? 本身也是一个Class类 
public enum EnumSingle { 
    INSTANCE; 
    
    public EnumSingle getInstance(){ 
        return INSTANCE; 
    } 
}

枚举类介绍:https://blog.youkuaiyun.com/hellojoy/article/details/79883671

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值