單例模式介紹
單例模式:?jiǎn)卫J綄儆诠S模式的特例,只是它不需要輸入?yún)?shù)并且始終返回同一對(duì)象的引用锣枝。單例模式能夠保證某一類型對(duì)象在系統(tǒng)中的唯一性,即某類在系統(tǒng)中只有一個(gè)實(shí)例。
單例模式中的兩種模式介紹
1.懶漢模式:顧名思義零远,他是一個(gè)懶漢,不愿動(dòng)彈烤宙。只有你主動(dòng)叫他的時(shí)候他才會(huì)工作遍烦,也就是說(shuō)實(shí)例在類加載的時(shí)候不被初始化,到了需要使用的時(shí)候才會(huì)進(jìn)行初始化躺枕。
2.餓漢模式:顧名思義服猪,他是一個(gè)餓漢供填,他很勤快就怕自己餓著。他總是先把食物準(zhǔn)備好罢猪,什么時(shí)候需要吃了近她,他隨時(shí)拿來(lái)吃,不需要臨時(shí)去搞食物膳帕。因此餓漢模式下實(shí)例在類加載時(shí)就完成了初始化粘捎,但是加載比較慢,獲取對(duì)象比較快危彩。
懶漢模式代碼實(shí)現(xiàn)
public class LazybonesSingleton {
//默認(rèn)不會(huì)實(shí)例化攒磨,什么時(shí)候用就什么時(shí)候new
private volatile static LazybonesSingleton instance = null;
private LazybonesSingleton() {
}
public static LazybonesSingleton getInstance() {
if (instance == null) {
//什么時(shí)候用就什么時(shí)候new
synchronized (LazybonesSingleton.class) {
//使用雙檢查機(jī)制確保instance不為空時(shí)候只會(huì)被同步鎖一次,減少使用鎖的消耗汤徽,
//而且保證instance只會(huì)被new一次娩缰,
if (instance == null) {
instance = new LazybonesSingleton();
}
}
}
return instance;
}
}
LazybonesSingleton采? volatile 關(guān)鍵字修飾也是很有必要的, instance = new LazybonesSingleton(); 這段代碼其實(shí)是分為三步執(zhí)行:
- 為
instance
分配內(nèi)存空間 - 初始化
instance
- 將
instance
指向分配的內(nèi)存地址
但是由于 JVM 具有指令重排的特性谒府,執(zhí)?順序有可能變成 1->3->2拼坎。指令重排在單線程環(huán)境下不會(huì)出現(xiàn)問題,但是在多線程環(huán)境下會(huì)導(dǎo)致?個(gè)線程獲得還沒有初始化的實(shí)例完疫。例如泰鸡,線程 T1 執(zhí)?了 1 和 3,此時(shí) T2 調(diào)? getInstance() 后發(fā)現(xiàn) instance
不為空壳鹤,因此返回instance
盛龄,但此時(shí) instance
還未被初始化。
使?
volatile
可以禁? JVM 的指令重排器虾,保證在多線程環(huán)境下也能正常運(yùn)?
餓漢模式代碼實(shí)現(xiàn)
public class HungrySingleton {
//一開始類加載的時(shí)候就進(jìn)行實(shí)例化讯嫂,創(chuàng)建單實(shí)例對(duì)象
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
}
單例中懶漢和餓漢的區(qū)別
(1) 線程安全:餓漢式在線程還沒出現(xiàn)之前就已經(jīng)實(shí)例化了,所以餓漢式一定是線程安全的兆沙。懶漢式加載是在使用時(shí)才會(huì)去new實(shí)例的欧芽,那么你去new的時(shí)候是一個(gè)動(dòng)態(tài)的過程,因此在new需要使用一些機(jī)制去保證創(chuàng)建實(shí)例時(shí)候的線程安全葛圃,例如上面代碼所使用的同步鎖+雙檢查機(jī)制千扔。
(2)執(zhí)行效率:餓漢式?jīng)]有加任何的鎖,因此執(zhí)行效率比較高库正。懶漢式一般使用都會(huì)加同步鎖曲楚,效率比餓漢式差。
(3)內(nèi)存使用:餓漢式在一開始類加載的時(shí)候就實(shí)例化褥符,無(wú)論使用與否龙誊,都會(huì)實(shí)例化,所以會(huì)占據(jù)空間喷楣,浪費(fèi)內(nèi)存趟大。懶漢式什么時(shí)候用就什么時(shí)候?qū)嵗资鳎焕速M(fèi)內(nèi)存。