關於DCL雙重鎖失效及解決方案

關於DCL雙重鎖失效及解決方案

 

Double  Check Lock (DCL)實現單例設計模式

DCL 方式實現單例的優勢是既可以在須要時才初始化單例,又可以保證線程安全,且單例對象初始化後調用getInstance方法不進行同步鎖。代碼以下:安全

本程序的 亮點天然在getInstance方法上面,能夠看到該方法對instance進行了兩次判空:第一層主要是爲了不沒必要要的同步,第二層判斷則是爲了在null狀況下才建立實例。這是什麼意思呢?是否是有點摸不着頭腦,下面就一塊兒來分析一下。併發

假設線程A執行到singleton03  = new Singleton03()語句,看起來只有一行代碼,但實際上它並非原子操做,這句代碼最終會被編譯成多條彙編指令,它大體作了3件事:函數

1)給singleton03的實例分配內存。高併發

2)調用Singleton03()構造函數,初始化成員字段。性能

3)將singleton03對象指向分配的內存空間(此時singleton03就不是null了)。spa

    可是,因爲Java編譯器容許處理器亂序執行,以及JDK1.5以前JMM中的Cache、寄存器到主內存回寫順序的規定,上面的2和3的順序是沒法保證的,也就是說,執行順序多是1-2-3也多是1-3-2。若是是後者,而且在3執行完畢、2未執行以前,被切換到線程B上,這時候singleton03由於已經在線程A內執行過了3,singleton03已是非空了,因此,線程B直接取走singleton03,再使用時就會出錯,這就是DCL失效問題,並且這種難以跟蹤難以重現的錯誤可能會隱藏好久。線程

    在JDK1.5以後,SUN官方已經注意到這種問題,調整了JVM,具體化了volatile關鍵字,所以,若是JDK1.5或以後的版本,只須要將singleton03的定義改爲private volatile static Singleton03 singleton = null就能夠保證singleton03對象每次都是從主內存中讀取,就可使用DCL的寫法來完成單例模式。固然,volatile或多或少也會影響到性能,但考慮到程序的正確性,這點犧牲也是值得的。設計

    DCL優勢:資源利用率高,第一次執行getInstance時單例對象纔會被實例化,效率高。缺點:第一次加載稍慢,也因爲JMM的緣由致使偶爾會失敗。在高併發環境下也有必定的缺陷,雖然發送機率很小。DCL模式是使用最多的單例實現方式,它可以在須要時才實例化對象,而且能在絕大多數場景下保證對象的惟一性,除非你的代碼在併發場景比較複雜或低於JDK1.6版本下使用,不然,這種方式通常可以知足要求。對象

以上參考《源碼設計模式解析與實戰》之單例模式,記以溫習,如有不足,請多指教

相關文章
相關標籤/搜索