【多线程】-- 单例模式

单例模式

单例模式属于一种设计模式,它指当前类只允许有一个实例对象。缘由是可以想象当一个类非常大,实例化一个对象需要大量的内存空间,实例化多个对象的话内存是无法接受的。

单例模式有细分为饿汉模式和懒汉模式


饿汉模式

📢饿汉模式是指当前类的唯一实例已经准备好了,就等着调用了。

class Hungry {
    private static Hungry hungry = new Hungry();

    public static Hungry getHungry() {
        return hungry;
    }

    // 禁止外部创建实例
    private Hungry() {
    }
}
  • 线程安全问题:

    饿汉模式在多线程模式下是安全的。因为获取实例时,直接返回实例,没有读或者写操作,不涉及原子性等。


懒汉模式

📢懒汉模式是指需要实例则再去创建。

class Lazy {
    private static Lazy lazy;
    
    public static Lazy getLazy() {
        if (lazy == null) {
            lazy = new Lazy();
        }
        return lazy;
    }

    // 禁止外部创建实例
    private Lazy() {
    }
}
  • 线程安全问题

    懒汉模式在多线程模式下是不安全的

    关键点集中在创建实例时要判断是否已经创建,这涉及到读操作,如果没有创建,则实例化对象,这涉及到写操作。

    安全问题:

    📌读写操作能否保证原子性?实例化会不会被指令重排序?

    原子性问题:如果多个线程并发进入load,则会创建多个实例。

原子性
指令重排序问题:“lazy = new Lazy();”,
实例化对象的过程主要涉及这几个步骤:
1.申请内存空间-->2.实例化对象,同时初始化内容-->3.引用赋值。

编译器可能会对步骤2和3进行优化,颠倒顺序,即进行指令重排序。

指令重拍序的问题在于如果是单线程,那么可以保证引用初次访问对象前进行步骤3初始化。但是在多线程的情况下,如果在步骤2完成后,那么会从synchronized中出去,其他线程则会进来,当这个线程判断不为空后,它得到这个为初始化的对象就会使用了,那么只要这个使用在步骤2完成前,那么一定会出现问题

在这里插入图片描述

📈✔优化:

class Lazy {
    private volatile static Lazy lazy; // 优化一
    private static final Object locker = new Object();

    public static Lazy getLazy() {
        if (lazy == null) {
            synchronized (locker) { // 优化二
                if (lazy == null) {
                    lazy = new Lazy();
                }
            }
        }
        return lazy;
    }

    // 禁止外部创建实例
    private Lazy() {
    }
}

📌注解:

  1. synchronized和volatile的作用
    • synchronized使得并发线程进行竞争,保证线程安全,同时保证原子性。
    • volatile保证不会被指令重排序。
  2. 为什么要双层if?
    • 外部的if是为了减少锁竞争,如果对象不空则不用等待锁。如果外部if去掉,多个线程直接竞争锁,不管你是否已经实例化了,都得竞争一下子,这样效率比较低!!!

    • 内部的if是为了判断是否实例化对象,主要针对哪些在未实例化之前并发进入竞争锁的哪些线程。如果内部if去掉,多个线程进入竞争锁后,那么一定会多次创建对象!!!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值