Java設計模式---單例模式
參考於 :
大話設計模式
java三百集---高淇
講在開頭:如果需要懶載入,推薦使用靜態內部類實現
如果不需要懶載入,推薦使用列舉
1.單例模式的概念
保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
你可能會想,我在建立物件的時候,先判斷是不是null,不是null就直接獲得,是null就建立例項。
“生孩子還是不生孩子”應該是夫妻的責任,而不是我的責任。如果按照上面的想法,那麼我就需要先判斷一下才可以,這樣“能不能生”就成了我的責任了哦。
我們把“生一個孩子”的責任交給類,我們只需要去獲得就完事了。
2.第一種實現---餓漢式
JVM載入類的時候先例項化了
優點:JVM載入類是執行緒安全
缺點:不能懶載入
package com.dingyu; /** * 餓漢式單例模式 ,效率高 * 執行緒安全,不需要synchronized關鍵字,但是不能懶載入 * @author dingyu * */ public class Singleton01 { private static Singleton01 instance = new Singleton01(); private Singleton01() { } public static Singleton01 getSingleton() { return instance; } }
3.第二種實現---懶漢式
呼叫方法的時候再去建立例項
優點:懶載入
缺點:需要同步(不同步,如果執行緒a,執行緒b同時呼叫getSingleton(),相當於new了兩次),效率不高
package com.dingyu; /** * 懶漢式單例模式 * 優點:懶載入 * 缺點:需要同步 * @author dingyu * */ public class Singleton02 { private static Singleton02 instance = null; private Singleton02() { } private static synchronized Singleton02 getSingleton() { if (instance == null) instance = new Singleton02(); return instance; } }
4.第三種實現---雙重鎖定(儘量別用)
如果第一次獲得就加鎖,建立。其他的時候就直接返回就可以。
優點:效率高,可以懶載入
缺點: JVM內部的原因會出現不可預知的錯誤(本人還沒去了解原因,如果有知道的可以告訴我下,感謝)
為什麼要判斷兩次null,大話設計模式中解釋了:如果執行緒a,執行緒b,通過突破了第一層null,執行緒a獲得鎖,執行緒b等著。a建立了個例項,釋放鎖,b獲得鎖,繼續執行,如果沒有第二層null,那麼b仍然會建立一個例項,破壞單例模式。
package com.dingyu; /** * 雙重檢測鎖實現單例模式 * * @author dingyu * */ public class Singleton03 { private static Singleton03 instance = null; private Singleton03() { } public static Singleton03 getSingleton() { if (instance == null) { synchronized (Singleton03.class) { if (instance == null) { instance = new Singleton03(); } } } return instance; } }
5.第四種實現---靜態內部類(推薦)
靜態內部類是你用到他的時候,他才會載入,而且載入類的時候是執行緒安全的,不需要同步
優點:懶載入,效率高
package com.dingyu; /** * 靜態內部類實現單例模式 * @author dingyu * */ public class Singleton04 { private Singleton04() { } private static class SingletonInnerClass { private static Singleton04 instance = new Singleton04(); } private static Singleton04 getSingleton() { return SingletonInnerClass.instance; } }
6.第五種實現---列舉(推薦)
列舉很特殊,JVM幫我們實現的單例,天然是單例的
優點:效率高,反射破解不了
缺點:不能懶載入
package com.dingyu; /** * 列舉實現單例 列舉本來就是單例的 * * @author dingyu * */ public enum Singleton05 { INSTANCE; }