Java設計模式4:單例模式
阿新 • • 發佈:2018-12-27
Java設計模式4:單例模式
單例模式
這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。單例模式有以下特點:
1、單例類只能有一個例項 2、單例類必須自己建立自己的唯一例項 3、單例類必須給其他所有物件提供這一例項 下面看一下單例模式的寫法 餓漢式 顧名思義,餓漢式,就是使用類的時候不管用的是不是類中的單例部分,都直接創建出單例類,看一下餓漢式的寫法: public class SingleObject {
//建立 SingleObject 的一個物件
private static SingleObject instance = new SingleObject();
//讓建構函式為 private,這樣該類就不會被例項化
private SingleObject(){}
//獲取唯一可用的物件
public static SingleObject getInstance(){
return instance;
}
}
是否多執行緒安全:是
描述:這種方式比較常用,但容易產生垃圾物件。
優點:沒有加鎖,執行效率會提高。
缺點:類載入時就初始化,浪費記憶體。
懶漢式: public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 是否多執行緒安全:是
單例模式的好處 作為一種重要的設計模式,單例模式的好處有: 1、控制資源的使用,通過執行緒同步來控制資源的併發訪問 2、控制例項的產生,以達到節約資源的目的 3、控制資料的共享,在不建立直接關聯的條件下,讓多個不相關的程序或執行緒之間實現通訊
這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。單例模式有以下特點:
1、單例類只能有一個例項 2、單例類必須自己建立自己的唯一例項 3、單例類必須給其他所有物件提供這一例項 下面看一下單例模式的寫法 餓漢式 顧名思義,餓漢式,就是使用類的時候不管用的是不是類中的單例部分,都直接創建出單例類,看一下餓漢式的寫法: public class SingleObject {
描述:這種方式比較常用,但容易產生垃圾物件。
懶漢式: public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 是否多執行緒安全:是
描述:這種方式具備很好的 lazy loading,能夠在多執行緒中很好的工作,但是,效率很低,99% 情況下不需要同步。 優點:第一次呼叫才初始化,避免記憶體浪費。 缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。 getInstance() 的效能對應用程式不是很關鍵(該方法使用不太頻繁)。 雙檢鎖 雙檢鎖(Double Check Lock,簡稱DCL)的寫法: public class Singleton { private volatile static Singleton singleton; private Singleton (){} //防止外部建立例項 私有 public static Singleton getSingleton() { if (singleton == null) {//第一個鎖,如果沒有例項 synchronized (Singleton.class) {//第二個鎖,如果沒有任何執行緒建立Singleton例項 物件鎖 - 若多個執行緒擁有同一個MyObject類的物件,則這些方法只能以同步的方式執行 if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } 執行緒A初次呼叫getSingleton()方法,判斷singleton為null,進入同步程式碼塊,此時執行緒切換到執行緒B,執行緒B呼叫getSingleton()方法,由於同步程式碼塊外面的程式碼還是非同步執行的,所以執行緒B走12行,判斷singleton為null,等待鎖。結果就是執行緒A例項化出了一個Singleton,釋放鎖,執行緒B獲得鎖進入同步程式碼塊,判斷此時singleton不為null了,並不例項化Singleton。這樣,單例類就保證了在記憶體中只存在一份。
登記式/靜態內部類:
這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。對靜態域使用延遲初始化,應使用這種方式而不是雙檢鎖方式。這種方式只適用於靜態域的情況,雙檢鎖方式可在例項域需要延遲初始化時使用。 public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } } 這種方式同樣利用了 classloader 機制來保證初始化 instance 時只有一個執行緒,它跟第 1 種方式不同的是:第 1 種方式只要 Singleton 類被裝載了,那麼 instance 就會被例項化(沒有達到 lazy loading 效果),而這種方式是 Singleton 類被裝載了,instance 不一定被初始化。因為 SingletonHolder 類沒有被主動使用,只有通過顯式呼叫 getInstance 方法時,才會顯式裝載 SingletonHolder 類,從而例項化 instance。想象一下,如果例項化 instance 很消耗資源,所以想讓它延遲載入,另外一方面,又不希望在 Singleton 類載入時就例項化,因為不能確保 Singleton 類還可能在其他的地方被主動使用從而被載入,那麼這個時候例項化 instance 顯然是不合適的。這個時候,這種方式相比第 1種方式就顯得很合理。列舉
public enum Singleton { INSTANCE; public void whateverMethod() { } } 一般情況下,不建議使用懶漢方式,建議使用餓漢方式。只有在要明確實現 lazy loading 效果時,才會使用登記方式。如果涉及到反序列化建立物件時,可以嘗試使用列舉方式。如果有其他特殊的需求,可以考慮使用雙檢鎖方式。單例模式的好處 作為一種重要的設計模式,單例模式的好處有: 1、控制資源的使用,通過執行緒同步來控制資源的併發訪問 2、控制例項的產生,以達到節約資源的目的 3、控制資料的共享,在不建立直接關聯的條件下,讓多個不相關的程序或執行緒之間實現通訊