大家好,我是Mic,一个没有才华只能靠颜值混饭吃的Java程序员。
今天给大家分享一道字节跳动的面试题。
“DCL单例模式设计为什么需要volatile修饰实例对象”
这也是一个比较常见的问题,涉及到多线程领域关于指令重排序的知识。
这个问题的高手回答,我整理到了一个10W字的面试文档里面,大家可以扫描文章尾端二维码领取。
下面看看高手的回答。
需要高手面试文档面试文档的小伙伴可以扫描文章底部二维码
我所理解的DCL问题,是在基于双重检查锁设计下的单例模式中,存在不完整对象的问题。
而这个不完整对象的本质,是因为指令重排序导致的。
当我们使用instance=new DCLExample()
构建一个实例对象的时候,因为new这个操作并不是原子的。
所以这段代码最终会被编译成3条指令。
为对象分配内存空间
初始化对象
把实例对象赋值给instance引用
由于这是三个指令并不是原子的。
按照重排序规则,在不影响单线程执行结果的情况下,两个不存在依赖关系的指令允许重排序,也就是不一定会按照代码编写顺序来执行。
这样一来就会导致其他线程可能拿到一个不完整的对象,也就是这个instance已经分配了引用实例,但是这个实例的初始化指令还没执行。
解决办法就是可以在instance这个变量上增加一个volatile关键字修饰,
volatile底层使用了内存屏障机制来避免指令重排序。
这个问题以前的考察频率还挺高的。
主要还是对线程安全性层面的指令重排序,以及volatile关键字的考察。
在Java并发编程里面,volatile很重要。
在AQS、ConcurrentHashMap等涉及到并发相关的工具都有用到。
另外,我将所有Java面试系列制作成了完整的面试文档。它的便捷之处在于,可以通过检索的方式,找到你想要的面试题,目前已经更新180期,总计超过15W字!