關於單例模式,可能是23種模式裡面最容易理解的一種模式了,這篇文章裡主要是整理了一下從網上搜集的材料,文字部分大部分直接從網上拷貝而來。中間有部分自己的理解。
單例模式,也叫單子模式,是一種常用的軟體設計模式。在應用這個模式時,單例對象的類必須保證只有一個執行個體存在。許多時候整個系統只需要擁有一個的全域對象,這樣有利於我們協調系統整體的行為。比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例對象統一讀取,然後服務進程中的其他對象再通過這個單例對象擷取這些配置資訊。這種方式簡化了在複雜環境下的組態管理。
實現單例模式的思路是:一個類能返回對象一個引用(永遠是同一個)和一個獲得該執行個體的方法(必須是靜態方法,通常使用getInstance這個名稱);當我們調用這個方法時,如果類持有的引用不為空白就返回這個引用,如果類保持的引用為空白就建立該類的執行個體並將執行個體的引用賦予該類保持的引用;同時我們還將該類的建構函式定義為私人方法,這樣其他處的代碼就無法通過調用該類的建構函式來執行個體化該類的對象,只有通過該類提供的靜態方法來得到該類的唯一執行個體。
單例模式適合於一個類只有一個執行個體的情況,比如視窗管理器,列印緩衝池和檔案系統,它們都是原型的例子。典型的情況是,那些對象的類型被遍及一個軟體系統的不同對象訪問,因此需要一個全域的訪問指標,這便是眾所周知的單例模式的應用。當然這隻有在你確信你不再需要任何多於一個的執行個體的情況下。
儘管單例設計模式如在下面的圖中的所顯示的一樣是最簡單的設計模式,但對於粗心的Java開發人員來說卻呈現出許多缺陷。
在《設計模式》一書中,作者這樣來敘述單例模式的:確保一個類只有一個執行個體並提供一個對它的全域訪問指標。
說明了單例模式的類圖。
單例模式的類圖
正如你在中所看到的,這不是單例模式的完整部分。此圖中單例類保持了一個對唯一的單例執行個體的靜態引用,並且會從靜態getInstance()方法中返回對那個執行個體的引用。
很多人都會寫的一種單例類型:
public class Singleton {private static Singleton INSTANCE = null;private Singleton(){}public static Singleton getInstance(){if(singleton == null){INSTANCE = new Singleton();}return INSTANCE;}}
但是這種單例類型在多線程中是不安全。有可能會出現兩個INSTANCE.為什麼呢?
如果當唯一執行個體尚未建立時,有兩個線程同時調用建立方法,那麼它們同時沒有檢測到唯一執行個體的存在,從而同時各自建立了一個執行個體,這樣就有兩個執行個體被構造出來,從而違反了單例模式中執行個體唯一的原則。 解決這個問題的辦法是為指示類是否已經執行個體化的變數提供一個互斥鎖(雖然這樣會降低效率)。
懶漢式單例模式:
public class Singleton { private static Singleton INSTANCE = null; // Private constructor suppresses // default public constructor private Singleton() {} //thread safe and performance promote public static Singleton getInstance() { if(INSTANCE == null){ synchronized(Singleton.class){ //if 2 or more thread go into first null check at same time , it will be instance more then once.so we must check it again. if(INSTANCE == null){ INSTANCE = new Singleton(); } } } return INSTANCE; } }
還有另外一個方法(也被稱為餓漢式單例模式):
public class Singleton { private final static Singleton INSTANCE = new Singleton(); // Private constructor suppresses private Singleton() {} // default public constructor public static Singleton getInstance() { return INSTANCE; } }
這樣寫就會避免出現兩個INSTANCE了。
比較:
- 餓漢式是安全執行緒的,在類建立的同時就已經建立好一個靜態對象供系統使用,以後不在改變。
- 懶漢式適合單線程,多線程情況下如果在建立執行個體對象時不加上synchronized則會導致對對象的訪問不是安全執行緒的。
- 從實現方式來講他們最大的區別就是懶漢式是延時載入,
他是在需要的時候才建立對象,而餓漢式在載入類時建立執行個體。
餓漢式無需關注多線程問題、寫法簡單明了、能用則用。但是它是載入類時建立執行個體(上面有個朋友寫錯了)、所以如果是一個原廠模式、緩衝了很多執行個體、那麼就得考慮效率問題,因為這個類一載入則把所有執行個體不管用不用一塊建立。 懶漢式的優點是延時載入、缺點是應該用同步。
如果這篇文章對您有用,勞煩幾秒鐘幫忙投下票:http://vote.blog.csdn.net/item/blogstar/aomandeshangxiao,Csdn 2012部落格之星投票,謝謝!!!