模式導讀:數據庫
單例模式:保證一個類只有一個實例,而且可以提供一個訪問該實例的全局訪問點。緩存
優勢:因爲單例模式只生成一個實例,減小了系統性能開銷,當一個對象的產生須要比較多的資源時,如讀取配置,產生其餘依賴對象時,則能夠經過在應用啓動時直接產生一個單例對象,而後永久駐留內存的方式來解決。安全
單例模式能夠在系統設置全局的訪問點,優化環共享資源訪問,例如能夠設計一個單例類,負責全部數據表的映射處理。併發
參考類圖:性能
代碼實現:測試
常見的五種單例模式實現方式:優化
主要:spa
餓漢式:線程安全,調用效率高,不能延時加載。線程
1 package com.etc; 2 3 //餓漢式單例模式,不可延時加載,調用效率高 4 public class HungrySingleton { 5 // 類初始化時當即加載這個對象,加載類時自然的是線程安全的 6 private static HungrySingleton instance = new HungrySingleton(); 7 8 // 讓構造器爲 private,這樣該類就不會被實例化 9 private HungrySingleton() { 10 } 11 12 // 獲取惟一可用的對象,方法沒有同步,調用效率高 13 public static HungrySingleton getInstance() { 14 return instance; 15 } 16 17 public void showMessage() { 18 System.out.println("餓漢式單例模式測試輸出:當即加載!"); 19 } 20 }
懶漢式:線程安全,調用效率不高,能夠延時加載。設計
1 package com.etc; 2 //懶漢式單例模式 3 public class LazySingleton { 4 //類初始化時,不初始化對象,延時加載 5 private static LazySingleton instance=null; 6 //私有化構造器 7 private LazySingleton() { 8 9 } 10 //設置了方法同步,每次調用該方法都要同步,併發效率低,資源利用率高 11 public synchronized static LazySingleton getInstance() { 12 //當須要使用時再初始化類對象 13 if(instance==null) { 14 instance=new LazySingleton(); 15 } 16 return instance; 17 } 18 public void showMessage() { 19 System.out.println("懶漢式單例模式測試輸出:延時加載!"); 20 } 21 }
其餘:
雙重檢測鎖式:因爲JVM底層內部模型緣由,偶爾會出問題,不建議使用。
1 package com.etc; 2 //雙重檢測鎖式單例模式 3 public class DCClockSingleton { 4 5 public static DCClockSingleton instance=null; 6 //私有化構造器 7 private DCClockSingleton() { 8 9 } 10 //將同步內容下放到if內部,提升了執行的效率,沒必要每次獲取對象都進行同步,只有第一次才同步建立了之後就沒必要同步 11 public static DCClockSingleton getInstance() { 12 if(instance ==null) { 13 DCClockSingleton ds; 14 //第一重檢測鎖 15 synchronized(DCClockSingleton.class) { 16 ds=instance; 17 if(ds==null) { 18 //第二重檢測鎖 19 synchronized(DCClockSingleton.class) { 20 if(ds==null) { 21 ds=new DCClockSingleton(); 22 } 23 } 24 instance=ds; 25 } 26 } 27 } 28 return instance; 29 } 30 public void showMessage() { 31 System.out.println("雙重檢測鎖單例模式測試輸出:延時加載!"); 32 } 33 }
靜態內部類式:線程安全,調用效率高,能夠延時加載。
1 package com.etc; 2 //靜態內部類單例模式 3 public class StaticNativeClassSingleton { 4 //私有化構造器 5 private StaticNativeClassSingleton() { 6 } 7 //靜態內部類,實現類的延時加載 8 private static class InstanceSingleton{ 9 private static final StaticNativeClassSingleton instance=new StaticNativeClassSingleton(); 10 } 11 //方法未同步,效率高 12 public static StaticNativeClassSingleton getInstance() { 13 return InstanceSingleton.instance; 14 } 15 public void showMessage() { 16 System.out.println("靜態內部類單例模式測試輸出:延時加載!"); 17 18 } 19 }
枚舉單例:線程安全,調用效率高,不能延時加載。
1 package com.etc; 2 //枚舉單例模式 3 public enum EnumSingleton { 4 //枚舉元素自己就是表明單例對象 5 instance; 6 public void showMessage() { 7 System.out.println("枚舉單例模式測試輸出:當即加載!"); 8 } 9 }
ps:測試類
1 package com.etc; 2 3 public class SingletonTest { 4 5 public static void main(String[] args) { 6 //餓漢式單例模式測試輸出 7 HungrySingleton hungry=HungrySingleton.getInstance(); 8 hungry.showMessage(); 9 //懶漢式單例模式測試輸出 10 LazySingleton lazy=LazySingleton.getInstance(); 11 lazy.showMessage(); 12 //雙重檢測鎖單例模式測試輸出 13 DCClockSingleton dcclock=DCClockSingleton.getInstance(); 14 dcclock.showMessage(); 15 //靜態內部類單例模式測試輸出 16 StaticNativeClassSingleton sns=StaticNativeClassSingleton.getInstance(); 17 sns.showMessage(); 18 //枚舉單例模式測試輸出 19 EnumSingleton e=EnumSingleton.instance; 20 e.showMessage(); 21 22 } 23 }
效果截圖:
單例模式優缺點:
優勢:
一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例。
二、避免對資源的多重佔用。
缺點:
沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。
適用場景:
一、要求生產惟一序列號。二、WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。三、建立的一個對象須要消耗的資源過多,好比 I/O 與數據庫的鏈接等。