溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

web設(shè)計(jì)模式中的單例模式是什么

發(fā)布時(shí)間:2021-11-15 11:10:05 來(lái)源:億速云 閱讀:199 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“web設(shè)計(jì)模式中的單例模式是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

單例模式 (Singleton Pattern)使用的比較多,比如我們的 controller 和 service 都是單例的,但是其和標(biāo)準(zhǔn)的單例模式是有區(qū)別的。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類的對(duì)象。

模式結(jié)構(gòu)

單例模式的結(jié)構(gòu)很簡(jiǎn)單,只涉及到一個(gè)單例類,這個(gè)單例類的構(gòu)造方法是私有的,該類自身定義了一個(gè)靜態(tài)私有實(shí)例,并向外提供一個(gè)靜態(tài)的公有函數(shù)用于創(chuàng)建或獲取該靜態(tài)私有實(shí)例。

源碼導(dǎo)讀

單例模式分為懶漢單例和餓漢單例;餓漢單例代碼很簡(jiǎn)單,顧名思義,餓漢單例就是類初始化的時(shí)候就將該單例創(chuàng)建,示例代碼如下:

public class Singleton {
	private static final Singleton singleton = new Singleton();
	//限制產(chǎn)生多個(gè)對(duì)象
	private Singleton(){	
	}
	//通過(guò)該方法獲得實(shí)例對(duì)象
	public static Singleton getSingleton(){
		return singleton;
	}
	//類中其他方法,盡量是 static
	public static void doSomething(){
	}
}

但是懶漢單例就不那么簡(jiǎn)單了,懶漢單例是在訪問(wèn)這個(gè)類的實(shí)例的時(shí)候先判斷這個(gè)類的實(shí)例是否創(chuàng)建好了,如果沒(méi)創(chuàng)建好就要先創(chuàng)建這個(gè)單例。也就是說(shuō)懶漢單例是第一次訪問(wèn)的的時(shí)候創(chuàng)建單例,而不是初始化階段。這將會(huì)導(dǎo)致一個(gè)問(wèn)題,如果在多線程場(chǎng)景下,多個(gè)線程同時(shí)訪問(wèn)這個(gè)單例都發(fā)現(xiàn)其未被創(chuàng)建,那么這些線程就會(huì)分別創(chuàng)建實(shí)例,那么這個(gè)單例模式就不那么單例了——實(shí)例被多次創(chuàng)建。在阿里開(kāi)發(fā)手冊(cè)中有兩條就是和懶漢單例相關(guān)的,告訴我們要如何去避免這種情況,第六節(jié)的第一條 和第十二條:

(六)并發(fā)處理

1.【強(qiáng)制】獲取單例對(duì)象需要保證線程安全,其中的方法也要保證線程安全。

說(shuō)明:資源驅(qū)動(dòng)類、工具類、單例工廠類都需要注意。

  1. 【推薦】在并發(fā)場(chǎng)景下,通過(guò)雙重檢查鎖(double-checked locking)實(shí)現(xiàn)延遲初始化的優(yōu)

化問(wèn)題隱患,推薦解

決方案中較為簡(jiǎn)單一種(適用于 JDK5 及以上版本),將目標(biāo)屬性聲明為 volatile 型。

反例:

class Singleton {  
	private Helper helper = null;  
	public Helper getHelper() {  
		if (helper == null) synchronized(this) {  
			if (helper == null)  
			helper = new Helper();  
		}  
		return helper;  
	}  
// other methods and fields...  

}

volatile 關(guān)鍵字的作用和雙重檢查鎖在我以往的博客中介紹過(guò),文章地址https://mp.weixin.qq.com/s/r52hmD71TtiJjlOzQUvRlA 這篇博客介紹了并發(fā)的一些知識(shí),小伙伴有空可以讀一讀。在這里 volatile 關(guān)鍵字的作用就是保證數(shù)據(jù)的可見(jiàn)性,雙重檢查鎖是提高代碼性能。下面我們分析一下手冊(cè)中的反例:

其中它的雙重檢測(cè)鎖指的是這段代碼:

if (helper == null) synchronized(this) {  
			if (helper == null)  
			helper = new Helper();  
		}

這里如果不用雙重檢測(cè)鎖的話只能在整個(gè) getHelper 方法上上鎖,因?yàn)檫@個(gè)方法必須要保證在并發(fā)情況下只有一個(gè)線程會(huì)執(zhí)行helper = new Helper(); ,這段代碼。也就是說(shuō)代碼 會(huì)成為這樣:

public synchronized Helper getHelper() {  
		if (helper == null)  {  
			if (helper == null)  
			helper = new Helper();  
		}  
		return helper;  
}

整個(gè)方法上鎖性能明顯是不好的,鎖的粒度變大了;雙重檢查鎖里面為什么要做兩次 if 判斷呢,這個(gè)問(wèn)題留給讀者思考,并不是特別難的問(wèn)題。但是反例里面沒(méi)有考慮到可見(jiàn)性的問(wèn)題——假設(shè)a線程和b線程同時(shí)訪問(wèn) getHelper 方法,然后 b 線程被阻塞住,a線程發(fā)現(xiàn)helper 未被實(shí)例化,于是執(zhí)行new方法,然后釋放鎖;此時(shí)b線程進(jìn)來(lái),或許我們直觀的感受是b線程發(fā)現(xiàn)屬性被實(shí)例化直接返回helper,但實(shí)際上不是,當(dāng)一個(gè)線程修改了線程共享的公共資源的時(shí)候(此處是helper屬性)其他線程未必會(huì)被通知到屬性被修改,因此b線程有可能發(fā)現(xiàn) helper 還是null 也有可能b線程知道 helper 被賦值了。使用volatile 就可以避免這種情況的發(fā)生。因此正確的代碼應(yīng)該是這樣的:

class Singleton {  
	private volatile Helper helper = null;  
	public Helper getHelper() {  
		······
	}  
// other methods and fields...  
}

“web設(shè)計(jì)模式中的單例模式是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

web
AI