拿一個對象創建賦值來說
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來禁止指令重排來保證單例線程安全。