单例模式的不同写法

/**
 * 懒汉式
 * 就是等到有线程调用getInstance这个方法时,才来创建对象实例
 */
public class Singleton01 {
    private Singleton01 instance = null;

    private Singleton01(){}

    public Singleton01 getInstance(){
        if (instance == null){
            instance =  new Singleton01();
        }
        return instance;
    }
}

/**
 * 双重检测机制
 * 当instance= =null时,假如有两个线程p1,p2进入了第一个if语句,之后p1进入的同步块中,成功创建了对象实例,
 * 这时候论到p2进入同步块,由于同步块还有一层if(instance= =null)的判断,
 * 又因为此时instance != null了,所以p2无法再创建新的实例对象。
 *
 * 通过volatile来保证指令重排问题
 * instance = new Singleton
 * 这段代码在虚拟机中是这样执行的:
 *
 * memory = allocate();//1: 给对象分配内存空间。
 *
 * ctorInstance(memory);//2: 初始化对象
 *
 * instance = memory; //3: 把instance变量指向刚刚分配的内存地址。
 *
 * 问题的根源就是指令重排的影响,可能执行顺序改变导致创建对象出现问题,
 * 所以我们只要保证在创建对象的时候,不要出现指令重排就可以了。
 * 只有把instance声明为volatile,那么虚拟机就会保证这三个动作按照顺序执行了,也就不会出现线程安全问题了。
 */
public class Singleton02 {
    private volatile Singleton02 instance = null;

    private Singleton02(){}

    public Singleton02 getInstance(){
        if (instance == null){
            synchronized (Singleton02.class){
                if (instance == null){
                    instance =  new Singleton02();
                }
            }
        }
        return instance;
    }
}

/**
 * 饿汉式
 * 就是一开始把对象实例创建出来,而不是等getInstance这个方法被调用才来创建对象
 *
 * 总结一下饿汉式的一些问题:
 *
 * 1、有可能出现对象白白浪费的情况。
 *
 * 2、和懒汉式一样,无法阻止反射问题。
 */
public class Singleton03 {
    private Singleton03 instance = new Singleton03();

    private Singleton03(){}

    public Singleton03 getInstance(){

        return instance;
    }
}

/**
 * 由于外部类无法访问静态内部类,因此只有当外部类调用Singleton.getInstance()方法的时候,才能得到instance实例。
 *
 * 并且,instance实例对象初始化的时机并不是在Singleton被加载的时候,而是当getInstance()方法被调用的时候,静态内部类才会被加载,这时instance对象才会被初始化。并且也是线程安全的。
 *
 * 所以,与饿汉式相比,通过静态内部类的方式,可以保证instance实例对象不会被白白浪费。
 *
 * 但是,它仍然存在反射问题。
 */
public class Singleton04 {
    private static class instanceHolder{
        private static Singleton04 instance = new Singleton04();
    }

    private Singleton04(){}

    public Singleton04 getInstance(){
        return instanceHolder.instance;
    }
}

/**
 * 和饿汉式一样,由于一开始instance实例就被创建了,所以有可能出现白白浪费的情况。
 *
 * 但是,通过枚举的方式,不仅代码简单,线程安全,而且JVM还能阻止反射获取枚举类的私有构造器。
 *
 * 线程安全:Java确保每个枚举常量只被实例化一次,在类加载时就完成实例化,这天然保证了线程安全。
 * 简单易用:使用枚举实现单例模式代码简洁,易于理解和实现。
 * 防止反射攻击:由于枚举类没有公开的构造器,因此无法通过反射来创建枚举类型的多个实例。
 * 防止序列化问题:枚举实例的序列化和反序列化不会创建新的对象,这保护了单例的状态。
 * 自动支持序列化机制:不需要显式实现序列化接口,枚举类型已经自动支持序列化和反序列化。
 */
public enum Singleton05 {
    instance;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值