詳細介紹單例模式

2020-08-10 18:00:44

首先我們來看看單例模式的定義:

單例模式是 Java 中最簡單的設計模式之一,屬於建立型模式,它提供了一種建立物件的最佳方式。單例模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。

(推薦教學:)

爲了保證記憶體中有且僅有一個物件,避免頻繁的建立物件造成對記憶體的消耗,讓所有需要呼叫這個物件的地方都使用這一個單例物件。

接下來我們看看單例模式的型別:

1、懶漢式

懶漢式指的是在需要使用的時候纔會去建立該單例物件。

懶漢式單例模式實現:

public class Singleton {
	private static Singleton singleton;
	private Singleton(){
	
	}
	public static Singleton getInstance(){
		if (singleton == null) {
			singleton = new Singleton();
	    }
	    return singleton;
}

對於懶漢式單例實現存在一個問題,就是如何確保只建立一個物件?若兩個或多個執行緒同時判斷singleton爲空,則會建立多個物件。因此我們需要解決執行緒安全問題。

說到執行緒安全想到的就是加鎖了,加鎖無非是在方法或者類物件上加鎖。

//在方法上加鎖
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	public static synchronized Singleton getInstance() {
    	if (singleton == null) {
        	singleton = new Singleton();
    	}
    return singleton;
	}
}

//在類物件上加鎖
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	public static Singleton getInstance() {
    synchronized(Singleton.class) {   
        if (singleton == null) {
            singleton = new Singleton();
        }
    }
    return singleton;
	}	
}

這兩個方法,能解決多執行緒同時建立單例物件的問題,但每次獲取物件都需要先獲取鎖,併發效能差。因此還需要優化,優化目標爲:如果沒有範例化物件,則加鎖建立,如果有範例化物件,則直接返回。

(學習視訊推薦:)

對於在方法上加鎖,無論是否存在範例化物件都需要加鎖。故我們需要優化的是在類物件上加鎖。

//DCL單例模式(Double Check + Lock)
public class Singleton {
	//volatite關鍵詞防止指令重排序,下文介紹
	private static volatile Singleton singleton;
	private Singleton(){}
	public static Singleton getInstance() {
	//如果singleton不爲空,則直接返回物件,若多個執行緒發現singleton爲空,則進入分支
		if (singleton == null) {
		//多個執行緒同時爭搶一個鎖,只有一個執行緒能成功,其他執行緒需等待
			synchronized(Singleton.class) {
			//爭搶到鎖的執行緒需再次判斷singleton是否爲空,因爲有可能被上個執行緒範例化了
			//若不爲空則範例化,後續執行緒再進入的時候則直接返回該物件
			//對於之後所有進入該方法的執行緒則無需獲取鎖,直接返回物件   
        	if (singleton == null) {
           		singleton = new Singleton();
        	}
    		}
		}
    	return singleton;
	}	
}

上述程式碼中新增了volatile關鍵詞防止指令重排序。

2、餓漢式

餓漢式指的是在類載入時即建立該單例物件。

餓漢式單例模式實現:

public class Singleton {
	private static final Singleton singleton = new Singleton();
	private Singleton(){
	
	}
	public static Singleton getInstance(){
		return singleton;
	}

總結:

懶漢式:需要時纔去範例化物件,在開發中如果對記憶體要求很高即採用懶漢式,在多執行緒環境下,應該使用DCL單例模式,使用DCL單例模式,解決了併發安全及效能低下的問題,若新增volatile關鍵詞還能防止指令重排序而發生的NPE異常。

餓漢式: 類載入時就已經範例化物件,如果對記憶體要求不高即採用餓漢式,簡單不易出錯,且沒有任何併發安全和效能問題。

以上就是詳細介紹單例模式的詳細內容,更多請關注php中文網其它相關文章!