zoukankan      html  css  js  c++  java
  • 双重检验的单例模式,为什么要用volatile关键字

    双重检验的单例模式是比较推荐的单例写法,在该代码中的单例对象的是用volatile关键字修饰的。这时就产生的一个疑问,为什么需要volatile来修饰呢?
    上网查看多个博客,下面简单通俗分析一下当中的原因:
    贴上不加volatile单例代码

    public class Singleton {
        private static Singleton s;
        private Singleton(){};
        public static Singleton getInstance() {  //1
            if(s == null) { //2
                synchronized (Singleton.class) { //3
                    if(s == null) { //4
                        s = new Singleton(); //5
                    }
                }
            }
            return s; //6
        }
    }

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

    以前不了解为什么需要volatile关键字,后来发现在并发情况下,如果没有volatile关键字,在第5行会出现问题
    对于第5行 s = new Singleton(); //5
    可以分解为3个步骤:

    1 memory=allocate();// 分配内存 相当于c的malloc
    2 ctorInstanc(memory) //初始化对象
    3 s=memory //设置s指向刚分配的地址

    上面的代码在编译器运行时,可能会出现重排序 从1-2-3 排序为1-3-2

    如此在多线程下就会出现问题

    例如现在有2个线程A,B

    线程A在执行第5行代码时,B线程进来,而此时A执行了 1和3,没有执行2,此时B线程判断s不为null 直接返回一个未初始化的对象,就会出现问题

    而用了volatile,上面的重排序就会在多线程环境中禁止,不会出现上述问题。
    正确双重检验单例模式写法:

    public class Singleton {
        private static volatile Singleton s;
        private Singleton(){};
        public static Singleton getInstance() {
            if(s == null) {
                synchronized (Singleton.class) {
                    if(s == null) {
                        s = new Singleton();
                    }
                }
            }
            return s;
        }
    }

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14

    总结:加上volatile就是为了防止产生指令的重排序问题
    为什么volatile能禁止指令的重排序呢?这里就涉及到volatile的原理了,这里就不多说volatile的原理,可以看看海子大神的博客:volatile关键字解析
    ---------------------
    作者:Tuzki_小辣鸡
    来源:CSDN
    原文:https://blog.csdn.net/weixin_37659242/article/details/82776198
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    FineReport图表、参数、填报、决策报表制作
    FineReport入门
    python时间计算:当天、前一天、月初、月末、季初、季末、半年初、半年末、年初、年末
    授予mysql的其他用户数据库的使用权限
    Python日志记录
    JStorm:概念与编程模型
    ftp传输图片损坏原因
    web应用中浏览器与服务端的编码和解码
    Http协议中的CharacterEncoding、Content-Encoding和Transfer-Encoding
    设计模式心法之单一职责原
  • 原文地址:https://www.cnblogs.com/tiancai/p/9927948.html
Copyright © 2011-2022 走看看