您好,登錄后才能下訂單哦!
本篇內(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ǎn)單,只涉及到一個(gè)單例類,這個(gè)單例類的構(gòu)造方法是私有的,該類自身定義了一個(gè)靜態(tài)私有實(shí)例,并向外提供一個(gè)靜態(tài)的公有函數(shù)用于創(chuàng)建或獲取該靜態(tài)私有實(shí)例。
單例模式分為懶漢單例和餓漢單例;餓漢單例代碼很簡(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)類、工具類、單例工廠類都需要注意。
【推薦】在并發(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í)用文章!
免責(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)容。