DCL单例模式是否需要加volatile

必须加volatile

**
 * 双重校验锁 DCL(DoubleCheckLock)
 * 必须加volatile 防止指令重排
 * 多线程情况下安全
 */
public class DCLType {
    // 增加volatile修饰禁止指令重排
    private static volatile DCLType INSTANCE;
    private DCLType() {
    }
    //可以整个方法加锁 但此时锁粒度太粗了,所以可降低锁粒度
    public static DCLType getInstance() {
        //进行了判断,如果有一个完成了new,就不用参与锁竞争,效率提高
        if (INSTANCE == null) {
            //如果等于空 进行上锁,上完锁再进行new 完了后释放锁
            //双重校验
            synchronized (DCLType.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new DCLType();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(DCLType.getInstance().hashCode());
            }).start();
        }
    }
}

原因:1.程序是存在乱序执行的   2.new一个对象的时候是存在半初始化状态的

假设thread 1  进行上锁,new申请内存空间,astore_1 和 invokespecial T.<init>这两步进行了指令重排,此时第二个线程进来了,此时thread 1 new了对象,进行INSTANCE==null判断,不为空,不需要上锁,直接拿到对象进行使用。此时INSTANCE处于半初始状态,第二个线程就使用了半初始化状态的对象。(虽然这种情况基本不存在,但还是要加volatile)volatile修饰的内存空间上面执行指令,会通过内存屏障完成禁止指令重排。最终的实现通过lock addl实现,锁总线完成volatile的两个功能,所有的CPU都这样锁。

内存屏障:

JVM(规范)级别的屏障:

LoadLoad屏障 (读):对于这样的语句 Load1;LoadLoad;Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

StoreStore屏障(写):Store1;StoreStore;Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其他处理器可见

LoadStore屏障 :同理,在后续写入操作被刷出前,保证前面要读取的数据被读取完毕

StoreLoad屏障 :同理,在后续读取操作执行前,保证之前写入对所有处理器可见。

jvm规定了8种happens-before原则,这八种之外的可重排序;

as-if-serial:看上去像有序执行,不管如何重排序,单线程执行结果不会改变;

硬件级别屏障

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Laughing_Xie

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

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

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

打赏作者

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

抵扣说明:

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

余额充值