單例模式中使用雙重檢查加鎖,強化單例思想

先上代碼:

  if (instance == null) { 
    synchronized(Singleton.class) { 
      if (instance == null)
        instance = new Singleton();
      } 
   } 
  return instance;
}```
#分析:
 - 線程1進入方法體,滿足條件instance == null,進入synchronized塊
 - 線程間搶占cpu資源,線程1被線程2預占,線程2進入方法體
 - 此時方法還沒執行完,對象還沒有創建出來instance依然為null
 - 線程2試圖獲取鎖資源,但線程1持有該鎖,于是線程2阻塞,線程2被線程1預占
 - 線程1繼續執行,此時instance 仍然為null,創建Singleton實例并將其引用賦值給instance,方法返回該實例對象的引用,退出方法
 - 線程1被線程2預占,線程2獲取鎖并檢查 instance是否為 null.由于instance 已經被賦值,所以不會創建第二個 Singleton 對象.
這樣一套雙重檢查加鎖機制實現了比普通單例模式更高效率的邏輯

###但是該雙重檢查加鎖機制也有不完美之處:
  雙重檢查鎖定并不能保證它會在單處理器或多處理器計算機上順利運行。          雙重檢查鎖定失敗的問題并不歸咎于JVM中的實現 bug,而是歸咎于 Java 平臺內存模型.內存模型允許所謂的“無序寫入”,這也是這些習語失敗的一個主要原因.
###最終采用以下代碼,才彌補了雙重檢查加鎖的機制的缺陷:
 ``` public static Singleton getInstance(){
    if (instance == null) {   
      synchronized(Singleton.class) {
        Singleton inst = instance; 
        if (inst == null) { 
          synchronized(Singleton.class) { 
          instance = new Singleton();
         } 
        }
       }
     }
     return instance;
  }```
####用 volatile 聲明每一個變量怎么樣?
另一個想法是針對變量 inst以及 instance使用關鍵字 volatile,根據 JLS(參見 參考資料),聲明成 volatile的變量被認為是順序一致的,即,不是重新排序的。但是試圖使用 volatile來修正雙重檢查鎖定的問題,會產生以下兩個問題:
這里的問題不是有關順序一致性的,而是代碼被移動了,不是重新排序。
即使考慮了順序一致性,大多數的 JVM 也沒有正確地實現 volatile
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容