DCL单例为什么要加Volatile
拿一个对象创建赋值来说
class T{ int elem = 1; } T t = new T();
上段代码转换成汇编码为:
0 new #2 <T> 3 dup 4 invokespecial #3 <T.<init>> 7 astore_1 8 return
从汇编码中可以看出,0行为对象开辟了一个内存空间,该内存的成员区包含整形变量elem,值初始为0(如果是引用或者指针变量则为空)。3行dup指令是在栈中复制一个对象的引用(在new的时候该栈中已经存在一个,执行dup后也就是两个了),第4行执行初始化,为对象成员变量赋值,这个时候会消耗一个引用并将它从栈中pop掉,这也是为什么要dup的原因。7行指令是将栈中的引用赋值给对象t,并在栈中pop掉该引用。8然后return。这个是整个汇编语言按源代码执行得过程。
但是cpu本质上得乱序执行,可能造成指令得重排,特别是在初始化对象指令上花费时间较多,可能进行了如下重排:
0 new #2 <T>
3 dup
7 astore_1
4 invokespecial #3 <T.<init>>
8 return
指令第7行可能在cpu执行是与第4行重排,那么当线程一从0开始执行,执行到第7行得时候将未初始化得对象得引用赋值给t,如果线程一挂起,线程二发现t的引用不为空在执行下面代码:if (t != null) xxxx->使用了半初始化得对象。会造成后续程序出错。所以用volatile来禁止指令重排来保证单例线程安全。