單例模式屬於建立型模式,保證在程序運行期間一個類只有一個實例,並提供一個全局訪問點java
推薦訪問個人我的網站,排版更好看呦:
https://chenmingyu.top/design-singleton/面試
單例模式目的是保證在程序運行期間一個類只有一個實例,並提供一個全局訪問點,不管什麼狀況下,只會生成一個實例,免去繁瑣的建立銷燬對象的過程。安全
如何設計單例模式其實很簡單,只須要考慮一個問題,實例是否能夠保證是全局惟一,只要知足這個條件,這個單例設計的確定就合格了。多線程
關於實例是否能夠保證是全局惟一的延伸出的問題:jvm
因此設計一個安全的單例須要考慮的問題仍是不少的。函數
針對上述問題常見的解決辦法:優化
實現一個最簡單的單例就須要考慮到以上的全部問題,這個時候什麼有用的方法還沒寫那,代碼就已經不少了,那有沒有簡單的辦法既知足上述條件,代碼又簡潔那,那確定有,使用枚舉實現單例。網站
常見的單例模式設計方案大概有五種,懶漢模式,餓漢模式,雙重檢查方式實現,靜態內部類實現,枚舉實現。線程
簡單的分個類:設計
其中懶漢模式,餓漢模式,雙重檢查方式實現,靜態內部類的實現方式均可以歸納爲如下兩步:
固然枚舉的實現方式最簡單,也最安全的,因此推薦使用枚舉實現,其次推薦使用靜態內部類方式實現。
不是延遲加載,加載類的時候直接初始化
/** * @auther: chenmingyu * @date: 2019/2/12 16:26 * @description: */ public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() { } public static Singleton getInstance(){ return singleton; } }
優勢:線程安全,代碼簡單。
缺點:不是延遲加載,若是你用不到這個類,它也會實例化,還有一個問題就是若是這個實例依賴外部一些配置文件,參數什麼的,在實例化以前就要獲取到,不然就實例化異常
延遲加載,首次須要使用的時候在實例化,須要考慮線程安全
線程不安全的實現方式
public class Singleton { private static Singleton singleton; private Singleton() { } public static Singleton getInstance(){ if(null == singleton){ singleton = new Singleton(); } return singleton; } }
線程安全的實現方式:
public class Singleton { private static volatile Singleton singleton; private Singleton() { } public static Singleton getInstance(){ if(null == singleton){ synchronized (Singleton.class){ if(null == singleton){ singleton = new Singleton(); } } } return singleton; } }
面試官:爲何使用volatile修飾singleton變量?
使用靜態內部類實現也是延遲加載,利用靜態內部類去實現線程安全,只有在第一次調用getInstance方法的時候纔會去加載SingletonHolder,初始化SINGLETON
public class Singleton { private Singleton() { } public static Singleton getInstance(){ return SingletonHolder.SINGLETON; } private static class SingletonHolder{ private static final Singleton SINGLETON = new Singleton(); } }
枚舉實現代碼更簡潔,線程安全,而且保證枚舉不會被反序列化,反射和克隆
/** * @auther: chenmingyu * @date: 2019/2/12 16:30 * @description: */ public enum Singleton { SINGLETON; /** * 提供的方法 */ public void method(){ System.out.println("枚舉實現"); } }
因此推薦使用枚舉方式,調用Singleton.SINGLETON.method();