單例設計模式——我是一條美麗的單身狗
一隻100KG的大菜鳥,正在努力學習中,如有出入,往大佬扶正,謝謝!!!
餓漢式 :
執行緒安全 ,如果單例用不到 ,造成了記憶體的開銷 .
publicclass HungrySingle { private static HungrySingle mHungrySingle = new HungrySingle(); private HungrySingle() { } public static HungrySingle getInstance() { return mHungrySingle; } }
懶漢式:
執行緒不安全的, 在多執行緒環境下, 並不能做到單例.
publicclass LazybonesSingle { private static LazybonesSingle mLazybonesSingle; //私有構造 private LazybonesSingle() { } //對外提供訪問方法 publicLazybonesSingle getInstance() { //如果兩個執行緒同時調永走到 ==null的時候可能會建立兩個物件 if (mLazybonesSingle == null) { mLazybonesSingle = new LazybonesSingle(); } return mLazybonesSingle; } }
懶漢式:
執行緒安全 ,獲取例項的時候,每次都走同步,造成了不必要的開銷.
public class LazybonesSingleSafe { private static LazybonesSingle mLazybonesSingle; private LazybonesSingleSafe() { } public synchronized static LazybonesSingle getInstance() { if (mLazybonesSingle == null) { mLazybonesSingle = new LazybonesSingle(); } return mLazybonesSingle; } }
DCL(雙重鎖驗證)式:
減少了每次同步的開銷 ,還保證了懶載入 ,但是在高併發的情況下,還有可能造成多例項的存在.
public class LazyboneSingleDCL { private static volatile LazyboneSingleDCL mLazyboneSingleDCL; private LazyboneSingleDCL() { } public static LazyboneSingleDCL getInstance() { //如果為空 進入同步不等空 直接取走物件減少了同步的開支 if (mLazyboneSingleDCL == null) { //如果為空 確保只有一個執行緒進入 synchronized (LazyboneSingleDCL.class) { //防止多執行緒 進入 再次判斷如果物件不為空 直接取值 if (mLazyboneSingleDCL == null) { mLazyboneSingleDCL = new LazyboneSingleDCL(); } } } return mLazyboneSingleDCL; } }
靜態內部類式:
java高併發,描述DCL是醜陋的,解決方案是用 靜態內部類來解決.
JVM的類載入方式(虛擬機器會保證一個類的初始化在多執行緒環境中被正確的加鎖、同步), 來保證了多執行緒併發訪問的正確性.
這種方式是一種比較完美的單例模式. 當然, 它也有其弊端, 依賴特定程式語言, 適用於JAVA平臺.
public class StaticInnerClassForm { private StaticInnerClassForm() { } public static StaticInnerClassForm getInstance() { return FormHolder.INSTANCE; } private static class FormHolder { private static StaticInnerClassForm INSTANCE = new StaticInnerClassForm(); } }
以上單例,存在一種情況可以再次建立物件反序列化以上方法為了不讓序列化建立物件 加入readResolve()方法 可以保證
列舉式:
單例,預設執行緒安全,任何情況下都保證物件唯一.
public enum SingletonEnum { INSTANCE; public void doSomething() { } }
容器單例式:
android的各種服務的單例使用Map來儲存的.
public class SingleMap { private static Map<String, Object> mSingMap = new HashMap<>(); private SingleMap() { } public void registerSingleService(String key, Object value) { if (!mSingMap.containsKey(key)) { mSingMap.put(key, value); } } public Object getService(String key) { //如果沒有這個值的要丟擲異常 return mSingMap.get(key); } }