目录
问题解答
DCL问题,是在基于双重检查锁设计下的单例模式中,存在不完整对象的问题。
而这个不完整对象的本质,是因为指令重排序导致的。
当我们使用instance=new DCLExample()构建一个实例对象的时候,因为new这个操作并不是原子的。
所以这段代码最终会被编译成3条指令(如图)。
1、为对象分配内存空间
2、初始化对象
3、把实例对象赋值给instance引用
由于这是三个指令并不是原子的(如图)。
按照重排序规则,在不影响单线程执行结果的情况下,两个不存在依赖关系的指令允许重排序,也就是不一定会按照代码编写顺序来执行。
这样一来,(如图) 就会导致其他线程可能拿到一个不完整的对象,也就是这个instance已经分配了引用实例,但是这个实例的初始化指令还没执行。
解决办法就是可以在instance这个变量上增加一个volatile关键字修饰,volatile底层使用了内存屏障机制来避免指令重排序。
面试点评
这个问题以前的考察频率还挺高的。
主要还是对线程安全性层面的指令重排序,以及volatile关键字的考察。
在Java并发编程里面,volatile很重要。
在AQS、ConcurrentHashMap等涉及到并发相关的工具都有用到。