單例模式(Singleton Pattern):確保某一個類只有一個實(shí)例,而且自行實(shí)例化并向整個系統(tǒng)提供這個實(shí)例榨咐,這個類稱為單例類彻秆,它提供全局訪問的方法。單例模式是一種對象創(chuàng)建型模式。
-
Singleton(單例)
在單例類的內(nèi)部實(shí)現(xiàn)只生成一個實(shí)例嫁蛇,同時它提供一個靜態(tài)的getInstance()工廠方法锨并,讓客戶可以訪問它的唯一實(shí)例;為了防止在外部對其實(shí)例化睬棚,將其構(gòu)造函數(shù)設(shè)計(jì)為私有第煮;在單例類內(nèi)部定義了一個Singleton類型的靜態(tài)對象解幼,作為外部共享的唯一實(shí)例。
但是這樣寫包警,并不能滿足只生成一個實(shí)例的要求撵摆。如果 Singleton的構(gòu)造方法中需要執(zhí)行耗時操作,那么當(dāng)?shù)诙握{(diào)用getInstance時害晦,為null的條件依然成立特铝,所以會產(chǎn)生多個實(shí)例。
以下是兩個優(yōu)化過后的單例模式
-
餓漢式單例模式
class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() { }
public static EagerSingleton getInstance() {
return instance;
}
}
當(dāng)類被加載時壹瘟,靜態(tài)的私有成員變量 instance 就被初始化鲫剿,并且只會創(chuàng)建一次,不會產(chǎn)生多個實(shí)例稻轨。
-
懶漢式單例模式
class LazySingleton {
private volatile static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
//第一重判斷
if (instance == null) {
//鎖定代碼塊
synchronized (LazySingleton.class) {
//第二重判斷
if (instance == null) {
instance = new LazySingleton(); //創(chuàng)建單例實(shí)例
}
}
}
return instance;
}
}
依靠synchronized關(guān)鍵字鎖定代碼塊灵莲,來確保多線程調(diào)用情況下的安全性,也不會產(chǎn)生多個實(shí)例殴俱。
餓漢式單例在類被加載的時候就實(shí)例化了自己政冻,確保了唯一性,也不用考慮多線程訪問的問題线欲。但是不管系統(tǒng)是否需要該實(shí)例對象明场,都會創(chuàng)建。且在系統(tǒng)剛加載的時候询筏,時間會增加榕堰。
懶漢式單例在第一次需要使用的時候才會創(chuàng)建實(shí)例,因此不會浪費(fèi)系統(tǒng)資源嫌套,并且通過雙重檢查鎖逆屡,volatile 等關(guān)鍵字來控制,會影響系統(tǒng)性能踱讨。
-
java語言最好的單例模式寫法 Initialization Demand Holder (IoDH)
//Initialization on Demand Holder
class Singleton {
private Singleton() {
}
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
}
由于靜態(tài)單例對象沒有作為Singleton的成員變量直接實(shí)例化魏蔗,因此類加載時不會實(shí)例化Singleton,第一次調(diào)用getInstance()時將加載內(nèi)部類HolderClass痹筛,在該內(nèi)部類中定義了一個static類型的變量instance莺治,此時會首先初始化這個成員變量,由Java虛擬機(jī)來保證其線程安全性帚稠,確保該成員變量只能初始化一次谣旁。由于getInstance()方法沒有任何線程鎖定,因此其性能不會造成任何影響滋早。