一個懶漢式單例緩存
1 public class Singleton { 2 private static volatile Singleton singleton = null; 3 4 private Singleton(){} 5 6 public static Singleton getSingleton(){ 7 if(singleton == null){ 8 synchronized (Singleton.class){ 9 if(singleton == null){ 10 singleton = new Singleton(); 11 } 12 } 13 } 14 return singleton; 15 } 16 }
這種編寫方式被稱爲「雙重檢查鎖」,主要在getSingleton()方法中,進行兩次null檢查。這樣能夠極大提高併發度,進而提高性能。畢竟在單例中new的狀況很是少,絕大多數都是能夠並行的讀操做,所以在加鎖前多進行一次null檢查就能夠減小絕大多數的加鎖操做,也就提升了執行效率。可是必須注意的是volatile關鍵字,該關鍵字有兩層語義。第一層語義是可見性,可見性是指在一個線程中對該變量的修改會立刻由工做內存(Work Memory)寫回主內存(Main Memory),因此其它線程會立刻讀取到已修改的值,關於工做內存和主內存可簡單理解爲高速緩存(直接與CPU打交道)和主存(平常所說的內存條),注意工做內存是線程獨享的,主存是線程共享的。volatile的第二層語義是禁止指令重排序優化,咱們寫的代碼(特別是多線程代碼),因爲編譯器優化,在實際執行的時候可能與咱們編寫的順序不一樣。編譯器只保證程序執行結果與源代碼相同,卻不保證明際指令的順序與源代碼相同,這在單線程並沒什麼問題,然而一旦引入多線程環境,這種亂序就可能致使嚴重問題。volatile關鍵字就能夠從語義上解決這個問題,值得關注的是volatile的禁止指令重排序優化功能在Java 1.5後才得以實現,所以1.5前的版本仍然是不安全的,即便使用了volatile關鍵字。安全