單例對象的類必須保證只有一個實例存在。許多時候整個系統只需要擁有一個的全局對象,這樣有利于我們協調系統整體的行為。
通常單例模式在Java語言中,有兩種構建方式:
- 懶漢式。指全局的單例實例在第一次被使用時構建。
- 餓漢式。指全局的單例實例在類裝載時構建。
以下方式均線程安全:
懶漢式(static)
不高效,因為在任何時候只能有一個線程調用 getInstance() 方法。但是同步操作只需要在instance == null調用時才被需要,即第一次創建單例實例對象時。雙重檢驗鎖改進。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懶漢式(static) | 雙重檢驗鎖(double checked locking pattern)
兩次檢查 instance == null,一次是在同步塊外,一次是在同步塊內。因為可能會有多個線程一起進入同步塊外的 if,如果在同步塊內不進行二次檢驗的話就會生成多個實例。此代碼也不完美,new Singleton()并非是一個原子操作。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null)
synchronized (Singleton.class) {
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
懶漢式(static) | 靜態內部類(static nested class)
推薦。
public class Singleton {
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
餓漢式(static final)
是一種懶加載模式(lazy initialization)。單例會在加載類后一開始就被初始化,即使客戶端沒有調用 getInstance()方法。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
枚舉式(Enum)
最簡單。
public enum Singleton {
INSTANCE;
}
總結
這篇博文只是自己梳理了一遍,有時間再完善完善。
參考資料
- 維基百科:單例模式
- 如何正確地寫出單例模式