单例模式

单例模式:
* 确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
* 有2种创建方式:懒汉模式 、饿汉模式

1)恶汉模式:在类加载时就创建好了对象,而不是在用到时候创建
# 由ClassLoad保证线性安全
public class HungrySingleton {

    private static HungrySingleton hungrySingleton = new HungrySingleton();
    
    /**
     * 私有化构造函数,不能被外部访问
     */
    private HungrySingleton() {}
    
    /**
     * 返回单例对象
     */
     public static HungrySingleton getHungrySingleton() {
        return hungrySingleton;
     }
}

2)懒汉模式:在第一次使用该对象时创建
--> 有问题的代码:线性不安全
public class LazySingleton {

    private static LazySingleton lazySingleton = null;
    
    /**
     * 私有化构造函数,不能被外部访问
     */
    private LazySingleton() {}
    
    /**
     * 返回单例对象
     */
     public static LazySingleton getlazySingleton() {
        if(lazySingleton == null){
            return new LazySingleton();
        }
        return lazySingleton;
     }
}

–> 改进:
双重锁检查:在加锁之前先判断 对象 == null 是否成立,如果不成立直接返回创建的,成立就加锁

	public class LazyDoubleCheckSingleton {

    /**
     * 使用volatile进行修饰,禁止指令重排
     */
    private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
    
    /**
     * 私有化构造函数,不能被外部访问
     */
    private LazyDoubleCheckSingleton() {}
    
    /**
     * 返回单例对象
     */
     public static LazyDoubleCheckSingleton getLazyDoubleCheckSingleton() {
        if(lazySingleton == null){
            synchronized(LazyDoubleCheckSingleton.class){
                if(lazySingleton == null){
                    return new LazyDoubleCheckSingleton();
                }
            }
        }
        return lazyDoubleCheckSingleton;
     }
}   

说明:

为什么需要对 lazyDoubleCheckSingleton 添加 volatile 修饰符
因为 lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); 不是原子性的,分为三步:
1) 为lazyDoubleCheckSingleton分配内存
2) 调用构造函数进行初始化
3) 将lazyDoubleCheckSingleton对象指向分配的内存【执行完这步 lazyDoubleCheckSingleton 将不为 null 】

为了提高程序的运行效率,编译器会进行一个指令重排,步骤2和步骤三进行了重排,线程1先执行了步骤一和步骤三,
执行完后,lazyDoubleCheckSingleton不为null,此时线程2执行到if (lazyDoubleCheckSingleton == null),
线程2将可能直接返回未正确进行初始化的lazyDoubleCheckSingleton对象。出错的原因主要是lazyDoubleCheckSingleton未正确初始化完成【写】,
但是其他线程已经读取lazyDoubleCheckSingleton的值【读】,使用volatile可以禁止指令重排序,通过内存屏障保证写操作之前不会调用读操作【执行if (lazyDoubleCheckSingleton == null)】

缺点 为了保证线程安全,代码不够优雅过于臃肿

-->改进:静态内部类
public class LazyStaticSingleton {
/**
 * 静态内部类
 * */
private static class LazyStaticSingletonHolder {
    private static LazyStaticSingleton lazyStaticSingleton = new LazyStaticSingleton();
}

/**
 * 构造函数私有化
 * */
private LazyStaticSingleton() {
}

public static LazyStaticSingleton getLazyStaticSingleton() {
    return LazyStaticSingletonHolder.lazyStaticSingleton;
}

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值