日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

漫画:什么是单例设计模式

發(fā)布時(shí)間:2023/12/3 asp.net 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 漫画:什么是单例设计模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載自?永遠(yuǎn)愛大家的 程序員小灰





—————? 第二天? —————















單例模式第一版:

1 2 3 4 5 6 7 8 9 10 11 public?class?Singleton?{ ????private?Singleton()?{}??//私有構(gòu)造函數(shù) ????private?static?Singleton?instance?=?null;??//單例對象 ????//靜態(tài)工廠方法 ????public?static?Singleton?getInstance()?{ ????????if?(instance?==?null)?{ ????????????instance?=?new?Singleton(); ????????} ????????return?instance; ????} }


為什么這樣寫呢?我們來解釋幾個(gè)關(guān)鍵點(diǎn):


1、要想讓一個(gè)類只能構(gòu)建一個(gè)對象,自然不能讓它隨便去做new操作,因此Signleton的構(gòu)造方法是私有的。


2、instance是Singleton類的靜態(tài)成員,也是我們的單例對象。它的初始值可以寫成Null,也可以寫成new?Singleton()。至于其中的區(qū)別后來會做解釋。


3、getInstance是獲取單例對象的方法。


如果單例初始值是null,還未構(gòu)建,則構(gòu)建單例對象并返回。這個(gè)寫法屬于單例模式當(dāng)中的懶漢模式。


如果單例對象一開始就被new?Singleton()主動構(gòu)建,則不再需要判空操作,這種寫法屬于餓漢模式


這兩個(gè)名字很形象:餓漢主動找食物吃,懶漢躺在地上等著人喂。







為什么說剛才的代碼不是線程安全呢?


假設(shè)Singleton類剛剛被初始化,instance對象還是空,這時(shí)候兩個(gè)線程同時(shí)訪問getInstance方法:




因?yàn)镮nstance是空,所以兩個(gè)線程同時(shí)通過了條件判斷,開始執(zhí)行new操作:





這樣一來,顯然instance被構(gòu)建了兩次。讓我們對代碼做一下修改:



單例模式第二版:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public?class?Singleton?{ ????private?Singleton()?{}??//私有構(gòu)造函數(shù) ???private?static?Singleton?instance?=?null;??//單例對象 ???//靜態(tài)工廠方法 ???public?static?Singleton?getInstance()?{ ????????if?(instance?==?null)?{??????//雙重檢測機(jī)制 ?????????synchronized?(Singleton.class){??//同步鎖 ???????????if?(instance?==?null)?{?????//雙重檢測機(jī)制 ?????????????instance?=?new?Singleton(); ???????????????} ????????????} ?????????} ????????return?instance; ????} }


為什么這樣寫呢?我們來解釋幾個(gè)關(guān)鍵點(diǎn):


1、為了防止new Singleton被執(zhí)行多次,因此在new操作之前加上Synchronized 同步鎖,鎖住整個(gè)類(注意,這里不能使用對象鎖)。


2、進(jìn)入Synchronized?臨界區(qū)以后,還要再做一次判空。因?yàn)楫?dāng)兩個(gè)線程同時(shí)訪問的時(shí)候,線程A構(gòu)建完對象,線程B也已經(jīng)通過了最初的判空驗(yàn)證,不做第二次判空的話,線程B還是會再次構(gòu)建instance對象。












像這樣兩次判空的機(jī)制叫做雙重檢測機(jī)制













————————————











假設(shè)這樣的場景,當(dāng)兩個(gè)線程一先一后訪問getInstance方法的時(shí)候,當(dāng)A線程正在構(gòu)建對象,B線程剛剛進(jìn)入方法:




這種情況表面看似沒什么問題,要么Instance還沒被線程A構(gòu)建,線程B執(zhí)行 if(instance == null)的時(shí)候得到false;要么Instance已經(jīng)被線程A構(gòu)建完成,線程B執(zhí)行 if(instance == null)的時(shí)候得到true。


真的如此嗎?答案是否定的。這里涉及到了JVM編譯器的指令重排


指令重排是什么意思呢?比如java中簡單的一句 instance = new Singleton,會被編譯器編譯成如下JVM指令:


memory =allocate();? ? //1:分配對象的內(nèi)存空間?

ctorInstance(memory);? //2:初始化對象?

instance =memory;? ? ?//3:設(shè)置instance指向剛分配的內(nèi)存地址?


但是這些指令順序并非一成不變,有可能會經(jīng)過JVM和CPU的優(yōu)化,指令重排成下面的順序:


memory =allocate();? ? //1:分配對象的內(nèi)存空間?

instance =memory;? ? ?//3:設(shè)置instance指向剛分配的內(nèi)存地址?

ctorInstance(memory);? //2:初始化對象?


當(dāng)線程A執(zhí)行完1,3,時(shí),instance對象還未完成初始化,但已經(jīng)不再指向null。此時(shí)如果線程B搶占到CPU資源,執(zhí)行??if(instance == null)的結(jié)果會是false,從而返回一個(gè)沒有初始化完成的instance對象。如下圖所示:







如何避免這一情況呢?我們需要在instance對象前面增加一個(gè)修飾符volatile。



單例模式第三版:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public?class?Singleton?{ ????private?Singleton()?{}??//私有構(gòu)造函數(shù) ???private?volatile?static?Singleton?instance?=?null;??//單例對象 ???//靜態(tài)工廠方法 ???public?static?Singleton?getInstance()?{ ???????if?(instance?==?null)?{??????//雙重檢測機(jī)制 ???????synchronized?(this){??//同步鎖 ?????????if?(instance?==?null)?{?????//雙重檢測機(jī)制 ???????????instance?=?new?Singleton(); ?????????????} ??????????} ???????} ???????return?instance; ????} }






The volatile keyword indicates that a value may change between different accesses, it prevents an optimizing compiler from optimizing away subsequent reads or writes and thus incorrectly reusing a stale value or omitting writes.





經(jīng)過volatile的修飾,當(dāng)線程A執(zhí)行instance = new Singleton的時(shí)候,JVM執(zhí)行順序是什么樣?始終保證是下面的順序:


memory =allocate();? ? //1:分配對象的內(nèi)存空間?

ctorInstance(memory);? //2:初始化對象?

instance =memory;? ? ?//3:設(shè)置instance指向剛分配的內(nèi)存地址?


如此在線程B看來,instance對象的引用要么指向null,要么指向一個(gè)初始化完畢的Instance,而不會出現(xiàn)某個(gè)中間態(tài),保證了安全。









幾點(diǎn)說明:


1、volatile關(guān)鍵字不但可以防止指令重排,也可以保證線程訪問的變量值是主內(nèi)存中的最新值。有關(guān)volatile的詳細(xì)原理,我在以后的漫畫中會專門講解。


2、本漫畫純屬娛樂,還請大家盡量珍惜當(dāng)下的工作,切勿模仿小灰的行為哦。


總結(jié)

以上是生活随笔為你收集整理的漫画:什么是单例设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。