本文來自:曹勝歡部落格專欄。轉載請註明出處:http://blog.csdn.net/csh624366188
單例模式屬於對象建立型模式,其意圖是保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。對一些類來說,只有一個執行個體是很重要的,雖然系統中可以有許多印表機,但卻只應該有一個印表機假離線,只應該有一個檔案系統和一個視窗管理器,一個數字濾波器只能有一個A/D轉換器,一個會計系統只能專用於一個公司。怎樣才能保證一個類只有一個執行個體並且這個執行個體易於被訪問,一個全域變數使得一個對象可以被訪問,但它不能防止你執行個體化多個對象,一個更好的方法是讓類自身負責儲存他的唯一執行個體。這個類可以保證沒有其他執行個體可以被建立,並且它可以提供一個訪問該執行個體的方法,這就是Singleton模式。
單例模式的要點
一是某個類只能有一個執行個體;
二是它必須自行建立這個執行個體;
三是它必須自行向整個系統提供這個執行個體。
實用性:在下面的情況下可以使用Singleton模式。
l 當類只能有一個執行個體而且客戶可以從一個眾所周知的訪問點訪問它時。
l 當這個唯一執行個體應該是通過子類化可擴充的,並且客戶應該無需更改代碼就能使用一個擴充的執行個體時。
類圖:
從上面的類圖中可以看出,在單例類中有一個建構函式 Singleton ,
但是這個建構函式卻是私人的(前面是“ - ”符號),
然後在裡面還公開了一個 GetInstance()方法,
通過上面的類圖不難看出單例模式的特點,從而也可以給出單例模式的定義:單例模式保證一個類僅有一個執行個體,同時這個類還必須提供一個訪問該類的全域訪問點。
下面來自:http://blog.csdn.net/zhengzhb/article/details/7331369,博主給出的單例模式的詳解不得不學習
單例模式根據執行個體化對象時機的不同分為兩種:一種是餓漢式單例,一種是懶漢式單例。餓漢式單例在單例類被載入時候,就執行個體化一個對象交給自己的引用;而懶漢式在調用取得執行個體方法的時候才會執行個體化對象。代碼如下:
餓漢式單例
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return singleton; } }
懶漢式單例
public class Singleton { private static Singleton singleton; private Singleton(){} public static synchronized Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; } }
單例模式的優點:
· 在記憶體中只有一個對象,節省記憶體空間。
· 避免頻繁的建立銷毀對象,可以提高效能。
· 避免對共用資源的多重佔用。
· 可以全域訪問。
適用情境:由於單例模式的以上優點,所以是編程中用的比較多的一種設計模式。我總結了一下我所知道的適合使用單例模式的情境:
· 需要頻繁執行個體化然後銷毀的對象。
· 建立對象時耗時過多或者耗資源過多,但又經常用到的對象。
· 有狀態的工具類對象。
· 頻繁訪問資料庫或檔案的對象。
· 以及其他我沒用過的所有要求只有一個對象的情境。
單例模式注意事項:
· 只能使用單例類提供的方法得到單例對象,不要使用反射,否則將會執行個體化一個新對象。
· 不要做斷開單例類對象與類中靜態引用的危險操作。
· 多線程使用單例使用共用資源時,注意安全執行緒問題。
關於java中單例模式的一些爭議:
單例模式的對象長時間不用會被jvm垃圾收集器收集嗎
看到不少資料中說:如果一個單例對象在記憶體中長久不用,會被jvm認為是一個垃圾,在執行垃圾收集的時候會被清理掉。對此這個說法,筆者持懷疑態度,筆者本人的觀點是:在hotspot虛擬機器1.6版本中,除非人為地斷開單例中靜態引用到單例對象的聯結,否則jvm垃圾收集器是不會回收單例對象的。
對於這個爭議,筆者單獨寫了一篇文章進行討論,如果您有不同的觀點或者有過這方面的經曆請進入文章單例模式討論篇:單例模式與垃圾收集參與討論。
在一個jvm中會出現多個單例嗎
在分布式系統、多個類載入器、以及序列化的的情況下,會產生多個單例,這一點是無庸置疑的。那麼在同一個jvm中,會不會產生單例呢?使用單例提供的getInstance()方法只能得到同一個單例,除非是使用反射方式,將會得到新的單例。代碼如下
Class c = Class.forName(Singleton.class.getName());
Constructor ct = c.getDeclaredConstructor();
ct.setAccessible(true);
Singleton singleton = (Singleton)ct.newInstance();
這樣,每次運行都會產生新的單例對象。所以運用單例模式時,一定注意不要使用反射產生新的單例對象。
懶漢式單例安全執行緒嗎
主要是網上的一些說法,懶漢式的單例模式是線程不安全的,即使是在執行個體化對象的方法上加synchronized關鍵字,也依然是危險的,但是筆者經過編碼測試,發現加synchronized關鍵字修飾後,雖然對效能有部分影響,但是卻是安全執行緒的,並不會產生執行個體化多個對象的情況。
單例模式只有餓漢式和懶漢式兩種嗎
餓漢式單例和懶漢式單例只是兩種比較主流和常用的單例模式方法,從理論上講,任何可以實現一個類只有一個執行個體的設計模式,都可以稱為單例模式。
單例類可以被繼承嗎
餓漢式單例和懶漢式單例由於構造方法是private的,所以他們都是不可繼承的,但是其他很多單例模式是可以繼承的,例如登記式單例。
餓漢式單例好還是懶漢式單例好
在java中,餓漢式單例要優於懶漢式單例。C++中則一般使用懶漢式單例。
單例模式比較簡單,在此就不舉例代碼示範了。