雙重鎖實現單例時遭到質疑,既是:雙重鎖也無法保證單例模式! 果然,答案又是對方對的,汗顏! 原因是:指令會重排序,普通的變數僅僅會保證該方法在執行時,所有依賴的賦值結果是正確的,但不會保證執行順序! 為什麼會重排序:指令重排序是指cpu採用了允許將多條指令不按照程式的順序分開發送各相應電路單元處理, ...
雙重鎖實現單例時遭到質疑,既是:雙重鎖也無法保證單例模式!
果然,答案又是對方對的,汗顏!
原因是:指令會重排序,普通的變數僅僅會保證該方法在執行時,所有依賴的賦值結果是正確的,但不會保證執行順序!
為什麼會重排序:指令重排序是指cpu採用了允許將多條指令不按照程式的順序分開發送各相應電路單元處理,cpu不會任意排序(深入java虛擬機第12章),但需要重排序提高性能。
怎麼解決,標題也寫明白了。
使用volatile關鍵字!
為什麼使用volatile關鍵字可以實現:此關鍵字會禁止指令重排序,即:增加了記憶體屏障!
如果是一個cpu記憶體屏障是毫無意義的,如果是多cpu訪問同一塊記憶體,並且其中一個在觀測另一個,就需要記憶體屏障來保證一執行了。
如果你打開編譯後的代碼清單,會看到加入volatile關鍵字的變數會多一條指令:lock addl $0x0 ,(%esp)
此指令很有意義:lock addl $0x0 指令的作用是使當前cpu的cache值寫入記憶體,該寫入操作也會引起其他cpu或者內核無效化其cache,既是是做了一個空操作(store、write),可以讓volatile變數對其他cpu立即可見!
1 public class Singleton { 2 3 private volatile static Singleton singleton = null; 4 5 public static Singleton getSingleton() { 6 if (singleton == null) { 7 synchronized (Singleton.class) { 8 if (singleton == null) { 9 singleton = new Singleton(); 10 } 11 } 12 } 13 return singleton; 14 } 15 }View Code
另外:volatile屏蔽指令重排序的語義,在jdk1.5中才被完全修複!