1.單例模式有什麼用處?java
有一些對象只能使用一個,例如:數據庫鏈接、線程池(threadpool)、緩存(cache)、對話框、處理偏好(preferences)設置和這側表(registry)的對象、日誌對象、充當打印機、顯卡等設備的驅動程序的對象,即用於管理共享的資源。這種對象只能有一個實例,製造多個會致使問題。數據庫
2.最經典的單例模式?緩存
/** * 1.利用一個私有靜態變量來記錄Singleton類的惟一實例; * 2.構造器聲明爲私有,只有Singleton類自己內部纔可調用; * 3.聲明共有靜態的方法getInstance()來實例化對象,並返回這個對象的實例; * 4.說明:若是咱們不須要這個實例,就不會調用getInstance()方法,那麼這個實例就不會產生, * 稱爲「延遲實例化(lazy instantiaze)」。這種作法對資源敏感的對象特別重要。 */ public class Singleton { private static Singleton sInstance; private Singleton(){} public static Singleton getInstance(){ if(sInstance == null){ sInstance = new Singleton(); } return sInstance; } }
3.單例模式定義--確保一個類只有一個實例,並提供一個全局訪問點。
安全
(1)全局訪問點即向外提供的獲取惟一實例的惟一入口,是共有靜態的,訪問它對比訪問通常的全局變量的優勢在於:單例中的全局訪問點能夠作到「延遲實例化」。多線程
(2)此時的單例可能遇到的麻煩--多線程ide
正以下圖中狀況所示,當有多個線程同時訪問該訪問點時,以兩個線程爲例,就會出現可能實例化兩個對象,這對於使用單例的地方可能引起災難呀...
spa
4.怎樣改善多線程狀況下的單例?線程
(1)不推薦的方法--synchronized日誌
同步getInstance()方法既簡單又有效,可是可能形成程序執行效率降低100倍,若是getInstance()被調用的頻繁,只能從新考慮其餘方法了;對象
(2)什麼都不作
沒錯,什麼都不作。若是應用程序能夠接受getInstance()形成的額外負擔,那就徹底能夠忘記這件事;
(3)使用「急切實例化(eagerly)」而非「延遲實例化」的作法
a.若是應用程序老是須要建立使用單例實例;
b.若是應用程序在建立運行時方面的負擔不過重;
此時可選擇「急切實例化」:
public class EagerlySingleton { /**在靜態初始化器中建立單例實例,保證了線程安全**/ private static EagerlySingleton eSingletonInstance = new EagerlySingleton(); private EagerlySingleton(){}; public static EagerlySingleton getInstance(){ return eSingletonInstance; } }
這個作法,依賴JVM在加載這個類時就建立這個惟一的單例實例,保證了任何線程在訪問這個靜態變量以前,該實例已經建立。
(4)用「雙重檢查加鎖(double checked locking)」,在getInstance()中減小使用同步
/** * 1.volatile確保實例化時,多個線程能正確的處理sInstance; * 2.判斷sInstance == null後在使用synchronized,且synchronized後在判斷一次sInstance == null * 3.雙重檢查加鎖不適用於1.4以及更早的版本的Java。 */ public class DoubleCheckSingleton { private volatile static DoubleCheckSingleton sInstance; private DoubleCheckSingleton(){} public static DoubleCheckSingleton getInstance(){ if(sInstance == null){ synchronized (DoubleCheckSingleton.class) { if(sInstance == null){ sInstance = new DoubleCheckSingleton(); } } } return sInstance; } }