單例模式
- 定義:確保一個類只有一個實例犀斋,而且自行實例化并向整個系統(tǒng)提供這個實例杏头。
- 使用場景:確保一個類有且只有一個對象的場景萝勤,避免產(chǎn)生多個對象消耗過多的資源荤傲,或者某種類型的對象只應該有且只有一個办龄。
- 關鍵點:
- 構造函數(shù)不對外開放烘绽,一般為 Private。
- 通過一個靜態(tài)方法或者枚舉返回單例類對象 俐填。
- 確保單例類的對象有且只有一個安接,尤其在多線程環(huán)境下。
- 確保單例類對象在反序列化時不會重新構建對象英融。
- 實現(xiàn)方式:
- 懶漢模式:
- 定義:懶漢模式是聲明一個靜態(tài)對象盏檐,并且在用戶第一次調(diào)用個體Instance時進行初始化歇式。
- 代碼實現(xiàn):
public class SingleCode { //懶漢模式 private static SingleCode instance; private SingleCode(){} public static synchronized SingleCode getInstance(){ if(instance == null ) { instance = new SingleCode(); } return instance; } }
- 優(yōu)點:單例只有在使用時才會被實例化,在一定程度上節(jié)約資源胡野。
- 缺點:第一次加載時需要即使進行實例化材失,反應稍慢,最大的問題時每次調(diào)用getInstance都進行同步硫豆,造成不必要的同步開銷龙巨。
- Double CheckLock(DCL)實現(xiàn)單利:
- 定義:DCL方式實現(xiàn)單例模式的優(yōu)點是既能夠在需要時才初始化單利,又能夠保證線程安全熊响,且單例對象初始化后調(diào)用getInstance不進行同步鎖旨别;
- 代碼實現(xiàn):
public class SingleCode { //DCL 實現(xiàn)單例模式 private static SingleCode instance = null; private static Object obj = new Object(); private SingleCode(){} public static SingleCode getInstance(){ if(instance == null) { //判斷是否為空避免不需要的同步 synchronized (obj) { if(instance == null ) { //為了在null 的情況下創(chuàng)建實例 instance = new SingleCode(); } } } return instance; } }
- 優(yōu)點:資源利用率高,第一次執(zhí)行getInstance時單例對象才會被實例化汗茄,效率高秸弛。
- 缺點:第一次加載時反應稍慢,也由于Java內(nèi)存模型的原因偶爾會失敗洪碳。
- 靜態(tài)內(nèi)部類單例模式:
- 代碼實現(xiàn):
public class SingleCode { //靜態(tài)內(nèi)部類實現(xiàn)單例模式 private SingleCode(){} public static SingleCode getInstance(){ return SingleHolder.instance; } /**靜態(tài)內(nèi)部類*/ private static class SingleHolder{ private static final SingleCode instance = new SingleCode(); } }
- 優(yōu)點:第一次調(diào)用getInstance方法會導致虛擬機加載SingleHolder類胆屿,這種方法不僅能夠確保線程安全,也能夠保證單例對象的唯一性偶宫,同時也延遲里單例的實例化非迹。
- 推薦使用的單例模式實現(xiàn)方式。
- 代碼實現(xiàn):
- 枚舉單例:
- 代碼實現(xiàn):
public enum SingleEnum{ INSTANCE; public void doSomething(){ System.out.put("do sth."); } }
- 優(yōu)點:寫法簡單纯趋,枚舉實例的創(chuàng)建是線程安全的憎兽,并且任何情況下它都是一個單例。
- 代碼實現(xiàn):
- 使用容器實現(xiàn)單例模式:
- 代碼實現(xiàn):
public class SingleManager { private static Map<String,Object> objMap = new HashMap<String, Object>(); private SingleManager(){} 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); } }
- 優(yōu)點 容器實現(xiàn)單例模式可以管理多種類型的單例吵冒,并且在使用時可以通過統(tǒng)一接口進行獲取操作纯命,降低用戶使用成本,有對用戶隱藏了具體實現(xiàn)痹栖,降低了耦合度亿汞。
- 代碼實現(xiàn):
- 懶漢模式:
總結
- 優(yōu)點:
- 由于單例模式在內(nèi)存中只有偶一個實例,減少內(nèi)存開支揪阿,特別是一個對象需要頻繁地創(chuàng)建疗我、銷毀時,而且創(chuàng)建或 銷毀時性能又無法優(yōu)化南捂。
- 由于單例模式只生成一個實例吴裤,所以減少系統(tǒng)的性能開銷。
- 單例模式可以避免對資源的多重占用溺健。
- 單例模式可以在系統(tǒng)設置全局的訪問點麦牺,優(yōu)化和共享資源訪問。
- 缺點:
- 單例模式一般沒有接口,擴展很困難剖膳,若要擴展除了修改代碼基本上沒有第二種途徑實現(xiàn)魏颓。
- 單例對象如果持有Context,那么很容引發(fā)內(nèi)存泄露吱晒,此時需要注意傳遞給單例對象的Context最好是Application Context琼开。