單例模式很簡單,但99%的人寫不對,
- 簡介
- 引入單例模式
- 將介紹哪些給你
- 何為單例模式
- 通俗的講
- 雙鎖檢測(DLC)版的單例模式
- 正確的寫法
- 易錯點
- 一、構造方法私有化
- 二、static關鍵字不能漏
- 三、instance需要private修飾
- 四、instance需要volatile修飾
- 五、雙檢測鎖實體化的邏輯
簡介
引入單例模式
單例模式概念特別簡單,我當初也想當然的覺得代碼真的顯而易見,當初學的時候連代碼都看的不仔細,所以很多次和別人交流的時候才發現原來還有很多沒有掌握,很多細節稍不注意就錯了,
將介紹哪些給你
為了節省篇幅,這篇博文不會介紹簡單的單例模式的實作方法,只會介紹雙所檢測版的單例模式的實作方法,并且指出有哪些很容易被忽視和出錯的技術細節,
何為單例模式
通俗的講
就是一個類,在一個應用程式里,只允許生成一個實體物件,
雙鎖檢測(DLC)版的單例模式
正確的寫法
雙檢測鎖(double check lock)單例模式,通俗來講就是需要進行兩次進行非空檢測,并且需要加鎖進行同步控制,是執行緒安全的單例模式實作方式之一;正確的代碼書寫方式之一如下,可能讀者會疑惑,為什么加鎖的代碼會這么復雜晦澀,其實他這樣設計是基于性能優化考慮的,稍后會分析,
public class DemoClazz{
private static volatile DemoClazz instance;
private DemoClazz(){}
public static DemoClazz getInstance(){
if(instance == null){
synchronized(DemoClazz.class){
if(instance == nul){
instance = new DemoClazz();
}
}
}
return instance;
}
}
易錯點
一、構造方法私有化
private DemoClazz(){}
構造方法必須私有化,我們學習java時都只見過public修飾的構造方法,但是構造方法是允許用private修飾的,
構造方法非私有化,會導致程式呼叫者可以私自呼叫構造方法實體化物件,從而破壞單例模式的特性,
二、static關鍵字不能漏
private static volatile DemoClazz instance;
public static DemoClazz getInstance(){}
getInstance()方法用來獲取單例,由于物件在類加載進來時是沒有實體物件存在的,所以只能通過static方法來獲取類實體,
同理static方法中訪問到的屬性均需要為類屬性(static修飾的屬性),所以用來存放實體物件參考的屬性instance用static修飾,
private static volatile DemoClazz instance;
三、instance需要private修飾
instance只有將訪問權限控制在本類方法中,才能保證邏輯的正確,如果用戶直接獲取instance,可能會獲取到一個null值,
四、instance需要volatile修飾
在 JVM的記憶體模型中,每個執行緒讀取和操作物件的屬性時,并不是直接在記憶體中操作,而是生成一個副本進行存取,volatile關鍵字可以保證現場之間對該變數保持可見性,即執行緒A對變數c的修改,執行緒B在下次讀取變數c時能立馬感知到,
盡管有關鍵字synchronized關鍵字,如果不加上volatile關鍵字,可能會導致在并發場景下執行緒各自生成了實體物件在各自的執行緒作業空間里,
五、雙檢測鎖實體化的邏輯
public static DemoClazz getInstance(){
if(instance == null){
synchronized(DemoClazz.class){
if(instance == nul){
instance = new DemoClazz();
}
}
}
return instance;
}
getInstance方法會進行兩次判空操作;第一次,判斷是否實體化了,有實體物件則直接回傳,不需要其他操作,如果沒有實體化,則說明是程式第一次去獲取實體對像,會進行一次加鎖操作,只允許一個執行緒進入方法,進入方法之后的判空操作是為了僅允許第一個進入的執行緒進行實體化,其他執行緒不允許實體化,
因為實體化操作僅需要進行一次同步,所以可以用第一次判空操作來進行避免,至于第二次判空操作,則是為了保證單例,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/179597.html
標籤:其他
