Java單例模式的6種實現方式詳解
為什麼使用單例模式
需要確保某個類隻要一個對象,或創建一個類需要消耗的資源過多,如訪問IO和數據庫操作等,這時就需要考慮使用單例模式瞭。
使用單例模式需要註意的關鍵點
- 將構造函數訪問修飾符設置為private
- 通過一個靜態方法或者枚舉返回單例類對象
- 確保單例類的對象有且隻有一個,特別是在多線程環境下
- 確保單例類對象在反序列化時不會重新構建對象
單例模式的幾種寫法
1. 餓漢式
/** * 餓漢式實現單例模式 */ public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
2. 懶漢式
/** * 懶漢式實現單例模式 */ public class Singleton { private static Singleton instance; private Singleton() { } // synchronized方法,多線程情況下保證單例對象唯一 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
getInstance()方法中添加瞭synchronized關鍵字,使其變成一個同步方法,目的是為瞭在多線程環境下保證單例對象唯一。
優點: 隻有在使用時才會實例化單例,一定程度上節約瞭資源。
缺點: 第一次加載時要立即實例化,反應稍慢。每次調用getInstance()方法都會進行同步,這樣會消耗不必要的資源。這種模式一般不建議使用。
3. DCL(Double CheckLock)實現單例
/** * DCL實現單例模式 */ public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { // 兩層判空,第一層是為瞭避免不必要的同步 // 第二層是為瞭在null的情況下創建實例 if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
優點: 資源利用率高,既能夠在需要的時候才初始化實例,又能保證線程安全,同時調用getInstance()方法不進行同步鎖,效率高。
缺點: 第一次加載時稍慢,由於Java內存模型的原因偶爾會失敗。在高並發環境下也有一定的缺陷,雖然發生概率很小。
DCL模式是使用最多的單例模式實現方式,除非代碼在並發場景比較復雜或者JDK 6以下版本使用,否則,這種方式基本都能滿足需求。
4. 靜態內部類
/** * 靜態內部類實現單例模式 */ public class Singleton { private Singleton() { } public static Singleton getInstance() { return SingletonHolder.instance; } /** * 靜態內部類 */ private static class SingletonHolder { private static Singleton instance = new Singleton(); } }
第一次加載Singleton類時不會初始化instance,隻有在第一次調用getInstance()方法時,虛擬機會加載SingletonHolder類,初始化instance。
這方式既保證線程安全,單例對象的唯一,也延遲瞭單例的初始化,推薦使用這種方式來實現單例模式。
5. 枚舉單例
/** * 枚舉實現單例模式 */ public enum SingletonEnum { INSTANCE; public void doSomething() { System.out.println("do something"); } }
默認枚舉實例的創建是線程安全的,即使反序列化也不會生成新的實例,任何情況下都是一個單例。
優點: 簡單!
6. 容器實現單例
import java.util.HashMap; import java.util.Map; /** * 容器類實現單例模式 */ public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String, Object>(); public static void regsiterService(String key, Object instance) { if (!objMap.containsKey(key)) { objMap.put(key, instance); } } public static Object getService(String key) { return objMap.get(key); } }
SingletonManager可以管理多個單例類型,使用時根據key獲取對象對應類型的對象。這種方式可以通過統一的接口獲取操作,隱藏瞭具體實現,降低瞭耦合度。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!