一篇看懂各种单例模式实现的优缺点

/**
 * 饿汉式
 * 优点:实现简单,类加载时就创建,线程安全
 * 缺点:类加载时创建,如果实例没有被使用,会造成内存浪费
 */
public class SingleInstance {
    private static final SingleInstance signalInstance = new SingleInstance();

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        return signalInstance;
    }
}

/**
 * 懒汉式 1
 * 优点:在需要是创建实例,减少了对内存的浪费
 * 问题:多线程下,不同线程获取的实例不一定是同一个
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        if (signalInstance == null) {
            // 此处可能多个线程同时进入,线程1和线程2可能同时创建不同的实例,导致线程1和线程2获取的实例不同
            signalInstance = new SingleInstance();
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 2
 * 优点:在需要是创建实例,减少了对内存的浪费,通过对方法加锁,解决了 懒汉式 1 中多线程遇到的问题
 * 缺点:由于对方法加了锁,导致性能下降
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static synchronized SingleInstance getInstance() {
	// 其它业务逻辑....
        if (signalInstance == null) {
            signalInstance = new SingleInstance();
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 3
 * 优点:解决了部分懒汉式 2 中的性能问题
 * 缺点:由于每次判断实例是否已经被初始化都需要加锁,导致性能下降
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务逻辑。。。。
        synchronized (SingleInstance.class) {
            if (signalInstance == null) {
                signalInstance = new SingleInstance();
            }
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 4
 * 优点:解决了 懒汉式3 中的性能问题
 * 问题:多线程获取实例的时候可能因为指令重排序导致线程获取实例内容不正确问题
 */
public class SingleInstance {
    private static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务代码。。。。
        if (signalInstance == null) { // 16行
            synchronized (SingleInstance.class) {
                if (signalInstance == null) {
                    // 多线程访问时,由于下面代码在创建实例的时候可能会存在指令重排序问题,导致 signalInstance 为空
                    /*
                    问题原因:
                    signalInstance = new SingleInstance() 执行的步骤是:
                        1.分配内存空间
                        2.赋默认值
                        3.将 signalInstance 指向分配的内存空间
                    由于指令重排序问题,步骤2和3可能会乱序,导致先执行步骤3,再执行步骤2,这个时候如果
                    有其他线程调用getInstance()方法,在执行16行判断的时候,signalInstance不为空,直接将实例返回了,
                    但返回的实例并不是正确赋值的实例
                     */
                    signalInstance = new SingleInstance();
                }
            }
        }
        return signalInstance;
    }
}

/**
 * 懒汉式 5
 * 优点:解决了懒汉式4中的指令重排序问题
 */
public class SingleInstance {
    /**
     * volatile 关键词可以禁止 signalInstance 在实例化过程中指令重排序
     */
    private volatile static SingleInstance signalInstance;

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // 其它业务代码。。。。
        if (signalInstance == null) {
            synchronized (SingleInstance.class) {
                if (signalInstance == null) {
                    signalInstance = new SingleInstance();
                }
            }
        }
        return signalInstance;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记忆旅途

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值