1. 程式人生 > >Java設計模式4:單例模式

Java設計模式4:單例模式

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;     } } 是否多執行緒安全:是

 

描述:這種方式具備很好的 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、控制資料的共享,在不建立直接關聯的條件下,讓多個不相關的程序或執行緒之間實現通訊