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来禁止指令重排来保证单例线程安全。

原文地址:https://www.cnblogs.com/lhdeng1991/p/12922451.html