介紹
單例模式作為我們是日常開發(fā)中最常見的集中設(shè)計(jì)模式之一绑洛,也是很多剛?cè)腴T的開發(fā)者最熟悉的設(shè)計(jì)模式宙址。單例模式保證了某個類的實(shí)例在系統(tǒng)中是唯一存在的混狠。
使用場景
一般用在創(chuàng)建某個類的對象需要消耗過多資源或者某個類的對象有且只能有一個的情況下忿等,例如IO訪問艇棕、網(wǎng)絡(luò)請求减俏、數(shù)據(jù)庫讀寫等召烂。
餓漢模式
public class Singleton {
private static final Singleton mInstance = new Singleton();
// 注意:構(gòu)造函數(shù)私有化
private Singleton() {
}
public static Singleton getInstance() {
return mInstacen;
}
}
餓漢模式下,不管你是否使用娃承,當(dāng)類初次被加載時實(shí)例就會被創(chuàng)建奏夫,后面每次調(diào)用不需要創(chuàng)建。從數(shù)據(jù)結(jié)構(gòu)上講历筝,用空間換取時間酗昼。
懶漢模式
非線程安全寫法
public class Singleton {
private static Singleton mInstance;
private Singleton() {
}
public static Singleton getInstance() {
if (mInstance == null) {
mInstance = new Singleton();
}
return mInstacen;
}
}
這種寫法一般情況下可以保證只有一個實(shí)例,但當(dāng)有多個線程同時訪問時漫谷,無法保證只有一個實(shí)例仔雷。
例如,當(dāng)mInstance為null時舔示,有A碟婆、B兩個線程同時訪問getInstance方法,假設(shè)線程A先進(jìn)入到if判斷中惕稻,并正在執(zhí)行mInstance = new Singleton()語句竖共。此時mInstance依舊為null,則B線程仍然可以進(jìn)入if判斷中俺祠,并執(zhí)行mInstance = new Singleton()語句公给。則此時便創(chuàng)建了兩個實(shí)例。
線程安全寫法
public class Singleton {
private static Singleton mInstance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (mInstance == null) {
mInstance = new Singleton();
}
return mInstacen;
}
}
該寫法保證了多線程下有且只有一個實(shí)例蜘渣。且只有在需要的時候才會實(shí)例化淌铐,從一定程度上節(jié)約了資源。但當(dāng)有多個線程同時訪問getInstance時蔫缸,在空間和時間上都造成了不必要的浪費(fèi)腿准。
例如,有A拾碌、B兩個線程同時訪問getInstance方法吐葱,假設(shè)線程A先進(jìn)入到getInstance方法中,由于synchronized的同步機(jī)制校翔,B線程必須等待A線程執(zhí)行完畢才能進(jìn)入到getInstance方法弟跑。假設(shè)線程很多,則每次都要進(jìn)行同步判斷防症,嚴(yán)重影響了執(zhí)行速度孟辑。
雙重鎖模式
public class Singleton {
private static Singleton mInstance;
private Singleton() {
}
public static Singleton getInstance() {
if (mInstance == null) {
synchronized (Singleton.class) {
if (mInstance == null) {
mInstance = new Singleton();
}
}
}
return mInstacen;
}
}
該模式不僅滿足了需要時才創(chuàng)建實(shí)例哎甲,節(jié)約了資源,更是線程安全的扑浸。且只有在第一次調(diào)用getInstance創(chuàng)建實(shí)例時才會同步檢查烧给,后面不再需要同步就能獲取到實(shí)例,加快了運(yùn)行速度喝噪。
例如础嫡,當(dāng)mInstance為null時,有A酝惧、B兩個線程同時訪問getInstance方法榴鼎,有以下兩種情況:
?1、當(dāng)A晚唇、B線程都進(jìn)入到第一個if判斷中巫财,由于synchronized同步機(jī)制,假設(shè)A線程先進(jìn)入第二個if判斷中哩陕,并且執(zhí)行了mInstance = new Singleton()語句返回了實(shí)例平项,這時當(dāng)B線程執(zhí)行到第二個if判斷時,會得到mInstance != null從而直接返回實(shí)例悍及。
?2闽瓢、當(dāng)A線程已經(jīng)進(jìn)入第二個if判斷中,并且執(zhí)行了mInstance = new Singleton()語句心赶,而B線程仍在第一個if判斷之外扣讼,則當(dāng)B線程執(zhí)行到第一個if判斷時,會得到mInstance != null從而直接返回實(shí)例缨叫。