單例模式
關鍵點
1.構造函數不對外開放,一般爲Private
2.通過一個靜態方法或者枚舉返回單例類對象
3.確保單例類的對象有且只有一個,尤其在多線程環境下
4.確保單例類對象在反序列化時不會重新構建對象
實現方式
1.懶漢模式
public void class Singleton {
private static Singleton sInstance;
private Singleton () {}
public static synchronized Singleton getInstance () {
if (sInstance == null) {
sInstance = new Songleton ();
}
return sInstance;
}
}
優點:使用時實例化,一定程度節約資源。
缺點:第一次使用需要實例化,速度較慢,每次調用 getInstance 都進行同步,造成不必要的開銷。
2.Double Check Lock - DCL
public void class Singleton {
private static Singleton sInstance = null;
private Singleton () {}
public static Singleton getInstance () {
if (sInstance == null) {
synchronized (Singleton.class) {
if (sInstance == null) {
sInstance = new Songleton ();
}
}
}
}
return sInstance;
}
優點:資源利用率高,第一次執行 getInstance 時纔會被實例化,效率高。
缺點:第一次加載較慢,會由於Java內存模型的原因偶爾失敗。高併發情況下也有缺陷,概率低。
造成失效原因(java編譯器允許亂序以及JDK1.5之前java內存模型中Cache、寄存器到主內存回寫順序的規定,1-2-3的順序無法保證,可能1-3-2.
JDK1.5或之後的版本加volatile規避)
1).給Singleton 的實例分配內存
2).調用Singleton() 的構造函數,初始化成員字段
3).將 sInstance 對象指向分配的內存空間
3.靜態內部類單例模式
public void class Singleton {
public static Singleton getInstance () {
return SingletonHolder .sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton ();
}
}
優點:保證線程安全,確保唯一性,同時延遲了單例的實例化,推薦。
4.枚舉單例
public enum SingletonEnum {
INSTANCE;
public void doSomething () {
System.out.println ("do some.");
}
}
在上述的幾種單例模式中,反序列化時它們都會重新創建對象,枚舉不存在此問題。
5.使用容器作爲單例模式
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<String, Object> ();
private SingletonManager () {}
public static void registerService (String key, Object instance) {
if(!objMap.containsKey(key) ) {
objMap.put(key ,instance);
}
}
public static Object getService (String, key) {
return objMap.get(key);
}
}
統一管理多種單例類型,降低耦合。
總結
優點:減少內存開支,性能開銷,避免對資源的多重佔用
*注意點:1) 拓展困難 . 2)若持有Context,防止內存泄露問題,傳入Application Context. *