double-checked-locking问题

  • 问题描述:观察如下实现单例的代码,当完成实例创建之后,再次调用getInstance方法时,还是会进入到同步代码块内部,而同步代码块属于重量级锁,性能较低,因此需要避免创建完实例后,反复进入同步代码块的情况发生
public final class Singleton1 {
    private Singleton1() {
        
    }

    private static Singleton1 INSTANCE = null;

    public static Singleton1 getINSTANCE() {
        synchronized (Singleton1.class) {
            if (INSTANCE == null) {
                INSTANCE = new Singleton1();
            }
            return INSTANCE;
        }
    }
}

  • 改进:使用双重锁,当未创建实例时,由同步代码块保证实例的单一。当创建完实例后,第一道锁(第一个if语句)可以避免代码反复进入到同步代码块之中
public final class Singleton1 {
    private Singleton1() {

    }

    private static Singleton1 INSTANCE = null;

    public static Singleton1 getINSTANCE() {
        if (INSTANCE == null) {
            synchronized (Singleton1.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton1();
                }
            }
        }
        return INSTANCE;
    }
}
  • 这样的改进在多线程环境下是有问题的,同步代码块内部可以保证原子性、顺序性、可见性,但是外部的if判断会出问题。详细分析

  • 简略分析:INSTANCE = new Singleton1();这个赋值语句包含了:1、取Singleton1的引用地址 2、调用1中引用地址的newInstance方法 3、将1中的地址赋值给INSTANCE

  • 其中执行顺序可以是123也可以是132,当JVM指令重排序结果为132时,假设t1线程执行完了1和3,这时cpu切换到t2线程,t2线程首先会去判断INSTANCE中的地址是否为空,由于第3步赋值了,因此if条件没有满足,因此会直接返回INSTANCE对象进行使用,但是线程t1还没有调用newInstance方法,就会发生错误

  • 解决方法:在INSTANCE前面加上volatile关键字:阻止指令重排序

public final class Singleton1 {
    private Singleton1() {

    }

    private static volatile Singleton1 INSTANCE = null;

    public static  Singleton1 getINSTANCE() {
        if (INSTANCE == null) {
            synchronized (Singleton1.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton1();
                }
            }
        }
        return INSTANCE;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值