以前我就知道單例模式的兩種寫法,如今經發現那兩種是很基礎的用法,下面分享一下,各種單例的寫法吧,我個人還是比較喜歡用枚舉類的方式寫單例,優雅簡潔,還安全。
Singleton 單例模式
第一種型式,餓漢式,在環境初始化,即JVM開始運行時就生成實例。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return Singleton.instance;
}
}
第二種型式,懶漢式,即需要使用時才生成實例,可以減少內存使用。
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
synchronized (Singleton.class) {
if(null == instance) {
instance = new Singleton();
}
}
return instance;
}
}
這種用了synchronized 傳說也會出現邏輯不嚴密而new出兩個實例的情況,所以又出現了一種變式,即雙重鎖機制,然而這種在苛刻的條件下依舊邏輯不夠嚴密。
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(null == instance) {
synchronized (Singleton.class) {
if(null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
第三種形式,枚舉形式,也是我現在比較常用的形式。
public enum Singleton {
INSTANCE;
public static Singleton getInstance() {
//do your Logic
// return INSTANCE;
}
}
這種方式除了更簡明,還等同於public屬性方式。免費提供了序列化機制,即使面對尖端的序列化或者反射攻擊,它都提供了堅實的單例。
第四種形式,延遲加載,解決鎖的同步問題,並且安全可靠。
public class SingletonFactory {
private static class SingletonHolder {
public static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
這種方式也是惰性初始化,在真正使用Holder時才初始化,而且因爲是靜態初始階段進行的,所以不再需要額外同步。
用這種方法解決延遲加載最合適不過了。
建議使用後兩種方式的單例形式,代碼看起來也很優雅 (以上示例private 的構造方法別忘記哦)。
這裏有一篇文章的測試代碼可以說明用第三種方式的堅實性和防止攻擊造成單例失效 http://lzh166.javaeye.com/blog/620817
另外,還有用反射等比較鑽牛角尖的方法構建單例的形式,以及一些測試,可以看一下這篇分析的文章 http://www.javaeye.com/topic/60179