單例模式定義
單例模式(Singleton),也叫單子模式,是一種常用的軟件設計模式。在應用這個模式時,單例對象的類必須保證只有一個實例存在。
單例模式的作用
許多時候整個系統只需要擁有一個的全局對象,這樣有利於我們協調系統整體的行爲方便管理,也使系統資源佔用率大大降低,也可以提高公共資源載入速度。
應用場景
比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然後服務進程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在複雜環境下的配置管理。需要頻繁的進行創建和銷燬的對象;創建對象時耗時過多或耗費資源過多,但又經常用到的對象;頻繁訪問數據庫或文件的對象。那麼可以初步歸納一下應用場景:
- 公用靜態資源類
如前端中模版頁、圖片鏈接等等 - 全局信息類
全局計數、環境變量、系統基本配置等 - 無狀態工具類
日誌工具、字符串工具、文件處理、圖片上傳等
單例模式的實現方法
餓漢式
public class Singleton {
private final static Singleton INSTANCE = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return INSTANCE; }
}
同靜態代碼塊方式:
public class Singleton {
private static Singleton instance; static { instance = new Singleton(); } private Singleton() {} public static Singleton getInstance() { return instance; }
}
因爲餓漢模式是靜態變量實例化,在類加載時候就會完成實例化,所有優勢和劣勢都比較明顯:
1.線程安全
2.在類加載的同時已經創建好一個靜態對象,調用時反應速度快
缺點:資源效率不高,可能getInstance()永遠不會執行到,但執行該類的其他靜態方法或者加載了該類(class.forName),那麼這個實例仍然初始化
懶漢式
//懶漢式單例類.在第一次調用的時候實例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//靜態工廠方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
這種寫法起到了Lazy Loading的效果,但是只能在單線程下使用。如果在多線程下,一個線程進入了if (singleton == null)判斷語句塊,還未來得及往下執行,另一個線程也通過了這個判斷語句,這時便會產生多個實例。所以在多線程環境下不可使用這種方式。
改進01
public class Singleton {
private static Singleton singleton; private Singleton() {} public static synchronized Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; }
}
解決上面第三種實現方式的線程不安全問題,做個線程同步就可以了,於是就對getInstance()方法進行了線程同步。缺點:效率太低了,每個線程在想獲得類的實例時候,執行getInstance()方法都要進行同步。而其實這個方法只執行一次實例化代碼就夠了,後面的想獲得該類實例,直接return就行了。方法進行同步效率太低要改進。
改進02-雙重檢查模式
public class Singleton {
private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }
}
靜態內部類方式
public class Singleton {
private Singleton() {} private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonInstance.INSTANCE; }
}
該方式在Singleton類被裝載時並不會立即實例化,而是在需要實例化時,調用getInstance方法,纔會裝載SingletonInstance類,從而完成Singleton的實例化。類的靜態屬性只會在第一次加載類的時候初始化,所以在這裏,JVM幫助我們保證了線程的安全性,在類進行初始化時,別的線程是無法進入的。
優點:避免了線程不安全,延遲加載,效率高。
枚舉式
public enum Singleton {
INSTANCE;
public void whateverMethod() {}
}
藉助JDK1.5中添加的枚舉來實現單例模式。不僅能避免多線程同步問題,而且還能防止反序列化重新創建新的對象。