前言:單例模式大家應該很熟悉了,我在這里就自己總結一下自己這段時間學到的單例相關的知識。
單例模式的目的:保證一個類只有單一的實例,也就是說你無法通過new來創建這個類的一個新實例。
單例模式的意義:保證一個類只有單一的實例,也就是說你無法通過new來創建這個類的一個新實例。我們可以控制類對象的產生的數目。
單例模式使用場合:
使用單例的情況有3種:
1、類a從類b繼承,這時a需使用單例才能直接訪問b中聲明的變量和方法
2、類a將被類b繼承,這時a也需要使用單例,否則b將無法直接使用a的方法
3、單例可以提供一個構造函數,確保使用該單例時能夠初始化一些環境,比如從外部讀入配置文件,或者和外部建立基本通信等
幾種實現方式(均為線程安全的實現方式):
1. 餓漢式:
public class Singleton { private Singleton(){ System.out.println("Singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
這種實現方式也被我們稱為餓漢式單例模式,宗旨就是不管你要不要,我先提前new出來,這肯定是線程安全的,因為new的動作發生在第一次訪問類的時候。
缺點:可能會出現不必要的實例化。也就是我不想獲取實例,它卻自己做了,這樣會降低效率。
例子:
public class Singleton { public static int STATUS=1; private Singleton(){ System.out.println("Singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
我僅僅想訪問Singleton里面的一個靜態字段,結果他還執行了一次new對象的操作。
2.同步方法:
public class LazySingleton { private LazySingleton() { System.out.println("LazySingleton is create"); } private static LazySingleton instance = null; public static synchronized LazySingleton getInstance() { if (instance == null) instance = new LazySingleton(); return instance; } }
這種方式雖然解決了線程安全和沒做多余的動作的要求,但是由於是在整個getInstance方法加了synchronized,導致一次只能一個線程調用getInstance方法,會影響程序運行效率。
3.同步代碼塊(Double Check)
public Resource getResource() { if (resource == null) { synchronized(this){ if (resource==null) { resource = new Resource(); } } } return resource; }
很不錯的解決方案,但是首先需要將單例聲明為volatile類型以保證線程安全,其次,用了同步代碼塊,所以也是會影響效率,不過比
之前幾個好很多。
4.內部靜態類:
public class StaticSingleton { private StaticSingleton(){ System.out.println("StaticSingleton is create"); } private static class SingletonHolder { private static StaticSingleton instance = new StaticSingleton(); } public static StaticSingleton getInstance() { return SingletonHolder.instance; } }
這種方式沒用到同步,但是很好的解決了之前幾種情況的缺點。