1. 程式人生 > 其它 >被Volatile修飾後的DCL(double check locking)懶漢式單例模式

被Volatile修飾後的DCL(double check locking)懶漢式單例模式

技術標籤:java多執行緒設計模式

單例模式核心思想: 構造器私有,提供static外部建立方法

  • DCL懶漢式(安全,執行緒同步): 每次建立物件的時候先對物件判斷一下,沒有這個物件的時候我再給你 這個物件,有的話就不給了,雙鎖結構(方法上鎖,內容上鎖)

    class LazySingle{
        //使用volatile保證變數的一致性 
        private volatile static LazySingle lazySingle=null; 
        public static LazySingle getInstance(){
          //為了解決程式碼中的效率問題,只有s為空的時候,才進入 synchronized的程式碼段,大大減少了機率
    if(lazySingle==null){ //防止多執行緒訪問,重複例項化 if(s==null){ //為了防可能出現多個例項的情況 synchronized(lazySingle.class){ if(lazySingle==null){ lazySingle = new lazySingle(); //不是原子性操作 /* 會經歷以下三步 1. 分配記憶體空間 2. 初始化物件 3. 把物件指向這個空間 */
    } } } return lazySingle; } private lazySingle(){} }
  1. volatile保證變數唯一性的原因,是因為new lazySingle()不是一個原子操作。可能在A執行緒的時候進行132步,B執行緒進行123步。當A執行緒正在把物件指向記憶體空間時,B執行緒執行到第一個判斷空的時候,發現為false,因為物件指向了S記憶體,此時B執行緒可能會認為lazySingle已經被建立(line6),就直接返回了instance例項,但此時instance並沒有初始化完全。所以上層在使用的時候會出現問題。
  2. 同步程式碼塊外加判空條件,這個判空是為了程式效率,全掉後導致效率變低。因為去掉之後,不管instance是否已經初始化,都會進行synchronized操作,而synchronized是一個重操作消耗效能。加上之後,如果已經初始化直接返回結果,不會進行synchronized操作。
  3. 同步程式碼塊里加判空條件,為了防止多執行緒情況下多次初始化例項,假設兩個執行緒a和b都通過了第一個判空條件。此時假設a先獲得鎖,進入synchronized的程式碼塊,初始化instance,a釋放鎖。接著b獲得鎖,進入synchronized的程式碼塊,也直接初始化instance,導致初始化了兩次,加上判空就可以防止這種情況發生