單例模式
- 定義:確保一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。
- 使用場景:確保一個類有且只有一個對象的場景,避免產(chǎn)生多個對象消耗過多的資源,或者某種類型的對象只應(yīng)該有且只有一個。
- 關(guān)鍵點:
- 構(gòu)造函數(shù)不對外開放,一般為 Private。
- 通過一個靜態(tài)方法或者枚舉返回單例類對象 。
- 確保單例類的對象有且只有一個,尤其在多線程環(huán)境下。
- 確保單例類對象在反序列化時不會重新構(gòu)建對象。
- 實現(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é)約資源。
- 缺點:第一次加載時需要即使進行實例化,反應(yīng)稍慢,最大的問題時每次調(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í)行g(shù)etInstance時單例對象才會被實例化,效率高。
- 缺點:第一次加載時反應(yīng)稍慢,也由于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):
- 懶漢模式:
總結(jié)
- 優(yōu)點:
- 由于單例模式在內(nèi)存中只有偶一個實例,減少內(nèi)存開支,特別是一個對象需要頻繁地創(chuàng)建、銷毀時,而且創(chuàng)建或 銷毀時性能又無法優(yōu)化。
- 由于單例模式只生成一個實例,所以減少系統(tǒng)的性能開銷。
- 單例模式可以避免對資源的多重占用。
- 單例模式可以在系統(tǒng)設(shè)置全局的訪問點,優(yōu)化和共享資源訪問。
- 缺點:
- 單例模式一般沒有接口,擴展很困難,若要擴展除了修改代碼基本上沒有第二種途徑實現(xiàn)。
- 單例對象如果持有Context,那么很容引發(fā)內(nèi)存泄露,此時需要注意傳遞給單例對象的Context最好是Application Context。