天天看點

四種單列模式設計模式之單例模式實作四:DCL雙檢查鎖機制(DCL:double checked locking)

設計模式之單例模式

什麼是單例設計模式?

單例模式,是一種常用的軟體設計模式。在它的核心結構中隻包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類隻有一個執行個體。即一個類隻有一個對象執行個體.

類結構圖

四種單列模式設計模式之單例模式實作四:DCL雙檢查鎖機制(DCL:double checked locking)

具體實作

需要:

(1)将構造方法私有化,使其不能在類的外部通過new關鍵字執行個體化該類對象。

(2)在該類内部産生一個唯一的執行個體化對象,并且将其封裝為private static類型。

(3)定義一個靜态方法傳回這個唯一對象。

實作一:立即加載 / “餓漢模式”

立即加載就是使用類的時候已經将對象建立完畢(不管以後會不會使用到該執行個體化對象,先建立了再說。很着急的樣子,故又被稱為“餓漢模式”),常見的實作辦法就是直接new執行個體化。

public class Singleton {

    // 将自身執行個體化對象設定為一個屬性,并用static、final修飾
    private static final Singleton instance = new Singleton();
    
    // 構造方法私有化
    private Singleton() {}
    
    // 靜态方法傳回該執行個體
    public static Singleton getInstance() {
        return instance;
    }
}
           

“餓漢模式”的優缺點:

優點:實作起來簡單,沒有多線程同步問題。

缺點:當類SingletonTest被加載的時候,會初始化static的instance,靜态變量被建立并配置設定記憶體空間,從這以後,這個static的instance對象便一直占着這段記憶體(即便你還沒有用到這個執行個體),當類被解除安裝時,靜态變量被摧毀,并釋放所占有的記憶體,是以在某些特定條件下會耗費記憶體。

實作二:延遲加載 / “懶漢模式”

延遲加載就是調用get()方法時執行個體才被建立(先不急着執行個體化出對象,等要用的時候才給你建立出來。不着急,故又稱為“懶漢模式”),常見的實作方法就是在get方法中進行new執行個體化。

public class Singleton {

    // 将自身執行個體化對象設定為一個屬性,并用static修飾
    private static Singleton instance;
    
    // 構造方法私有化
    private Singleton() {}
    
    // 靜态方法傳回該執行個體
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
           

“懶漢模式”的優缺點:

優點:實作起來比較簡單,當類SingletonTest被加載的時候,靜态變量static的instance未被建立并配置設定記憶體空間,當getInstance方法第一次被調用時,初始化instance變量,并配置設定記憶體,是以在某些特定條件下會節約了記憶體。

缺點:在多線程環境中,這種實作方法是完全錯誤的,根本不能保證單例的狀态。

實作三:線程安全的“懶漢模式”

public class Singleton {

    // 将自身執行個體化對象設定為一個屬性,并用static修飾
    private static Singleton instance;
    
    // 構造方法私有化
    private Singleton() {}
    
    // 靜态方法傳回該執行個體,加synchronized關鍵字實作同步
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
           

優點:在多線程情形下,保證了“懶漢模式”的線程安全。

缺點:衆所周知在多線程情形下,synchronized方法通常效率低,顯然這不是最佳的實作方案。

補充:

synchronized關鍵字的作用域有二種:

  1)是某個對象執行個體内,synchronized aMethod(){} 可以防止多個線程同時 通路這個對象的synchronized方法 (如果一個對象有多個synchronized方法,隻要一個線程通路了其中的一個synchronized方法,其它線程不能同時通路這個對象中任何一個synchronized方法 )。這時,不同的對象執行個體的 synchronized方法是不相幹擾的。也就是說,其它線程照樣可以同時通路相同類的另一個對象執行個體中的synchronized方法;

總的來說,這種情況,鎖就是這個方法所在的對象

2)是某個類的範圍,synchronized static aStaticMethod{} 防止多個線程同時通路這個類中的synchronized static 方法 。它可以對類的所有對象執行個體起作用。此時鎖就是這個class

實作四:DCL雙檢查鎖機制(DCL:double checked locking)

public class Singleton {

    // 将自身執行個體化對象設定為一個屬性,并用static修飾
    private static Singleton instance;
    
    // 構造方法私有化
    private Singleton() {}
    
    // 靜态方法傳回該執行個體
    public static Singleton getInstance() {
        // 第一次檢查instance是否被執行個體化出來,如果沒有進入if塊
	        if(instance == null) 
	        {
	            synchronized (Singleton.class) 
	            {
	                // 某個線程取得了類鎖,執行個體化對象前第二次檢查instance是否已經被執行個體化出來,如果沒有,才最終執行個體出對象
	                if (instance == null) {
	                    instance = new Singleton();
	            }
            }
        }
        return instance;
    }
}
           

方法四算是單例模式的最佳實作方式。記憶體占用率高,效率高,線程安全,多線程操作原子性。

補充:

除了方法前用synchronized關鍵字,synchronized關鍵字還可以用于方法中的某個區塊中,表示隻對這個區塊的資源實行互斥通路。

用法是: synchronized(this){/區塊/},鎖就是這個方法所在的對象 ;

原文:https://www.cnblogs.com/binaway/p/8889184.html

繼續閱讀