單例模式
單例(Singleton)模式的定義:一個類有且僅有一個實例,並且自行實例化向整個系統提供。例如,Windows 中只能打開一個任務管理器,這樣可以避免因打開多個任務管理器窗口而造成內存資源的浪費,或出現各個窗口顯示內容的不一致等錯誤。
在計算機系統中,還有 Windows 的回收站、操作系統中的文件系統、多線程中的線程池、顯卡的驅動程序對象、打印機的後臺處理服務、應用程序的日誌對象、數據庫的連接池、網站的計數器、Web 應用的配置對象、應用程序中的對話框、系統中的緩存等常常被設計成單例。
單例模式有 3 個特點:
-
單例類只有一個實例對象;
-
該單例對象必須由單例類自行創建;
-
單例類對外提供一個訪問該單例的全局訪問點;
1、飢餓式單例
該模式的特點: 類一旦加載就創建一個單例,保證在調用 getInstance 方法之前單例已經存在了。
是否 Lazy 初始化:否
是否多線程安全:是
實現難度:簡單
優點:沒有加鎖,執行效率會提高。
缺點:類加載時就初始化,浪費內存。
代碼如下:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
2、懶漢式單例
該模式的特點:類加載時沒有生成單例,只有當第一次調用 getlnstance 方法時纔去創建這個單例。
是否 Lazy 初始化:是
是否多線程安全:是
實現難度:複雜
描述:這種方式採用雙重加鎖機制,安全且在多線程情況下能保持高性能。
getInstance() 的性能對應用程序很關鍵。
代碼如下:
public class Singleton {
private volatile static Singleton instance = null;////保證 instance 在所有線程中同步
private Singleton() {//private 避免類在外部被實例化
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {//使用synchronized關鍵字來同步獲取實例,保證單例的唯一性
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
從上述代碼可以看到,雙重加鎖中有兩次判斷。第一次檢查是避免不必要的上鎖。相對加鎖的懶漢模式而言,第二次檢查是,在給當前線程加鎖後,例行檢查更加安全。
3、枚舉
默認枚舉實例的創建是線程安全的,並且在任何情況下都是單例。實際上
-
枚舉類隱藏了私有的構造器。
-
枚舉類的域 是相應類型的一個實例對象
是否 Lazy 初始化:否
是否多線程安全:是
實現難度:簡單
描述:這種實現方式還沒有被廣泛採用,但這是實現單例模式的最佳方法。它更簡潔,自動支持序列化機制,絕對防止多次實例化。這種方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還自動支持序列化機制,防止反序列化重新創建新的對象,絕對防止多次實例化。不過,由於 JDK1.5 之後才加入 enum 特性,用這種方式寫不免讓人感覺生疏,在實際工作中,也很少用。不能通過 reflection attack 來調用私有構造方法。
代碼如下:
public enum Singleton {
INSTANCE;
public void doSomethingMethod() {
}
}