單例模式深入學習1

單例模式的定義是保證一個類僅有一個實例饲握,并提供一個全局訪問點煌珊。一般用在工具類号俐、應用配置、數(shù)據(jù)庫連接池的創(chuàng)建上定庵。

優(yōu)點是一個類在內(nèi)存里只有一個實例吏饿,減少內(nèi)存開銷踪危,可以避免對資源的多重占用。

缺點是沒有借口猪落,無法擴展贞远。

單例模式的重點:私有構(gòu)造器、線程安全笨忌、延遲加載蓝仲、序列化和序列化安全、防止反射攻擊官疲。

單例模式分為餓漢模式和懶漢模式袱结。簡單的餓漢模式和懶漢模式的創(chuàng)建如圖。

餓漢模式


懶漢模式

餓漢模式是在類被加載時實例就已經(jīng)被創(chuàng)建途凫。若系統(tǒng)從始至終都未調(diào)用這個實例垢夹,則會造成資源浪費,再或者這個類的實例初始化比較占用資源维费,多個類都在加載時創(chuàng)建實例就會造成系統(tǒng)服務啟動慢果元。因此可以使用延遲加載,即初次調(diào)用時再初始化實例犀盟。注意的是兩種模式都需要將構(gòu)造器私有化而晒。

線程安全

而上圖所示懶漢模式是線程不安全的,如果只有一個線程調(diào)用這個類阅畴,的確只會初始化一個類欣硼。但如果多線程同時獲取實例,當兩個線程同時到達第10行恶阴,即判斷l(xiāng)azySingleton==null的時候诈胜,此時實例都未初始化,兩個線程同時判斷為true冯事,同時進入11行焦匈,去初始化實例,就會在過程中這個對象new了兩次£墙觯現(xiàn)在寫一個測試方法缓熟。


當直接執(zhí)行時,看到兩個線程獲取到的都是一個實例摔笤。


現(xiàn)在够滑,在懶漢模式的第10行判斷實例是否為空除打上斷點,并設置斷點為線程生效吕世。


debug執(zhí)行測試main函數(shù)彰触,兩個線程都執(zhí)行到第10行,都單步調(diào)試到第11行命辖,此時兩個線程都執(zhí)行結(jié)束况毅》直停可以看到debug干預下能復現(xiàn)可能出現(xiàn)的問題:過程中存在兩個實例。

如何消除這個隱患尔许?

synchronized給方法加鎖

第一種方式是在獲取實例的方法加上關鍵字synchronized么鹤,給方法加鎖,讓方法變成同步方法味廊。而此處獲取獲取實例的方法是靜態(tài)方法蒸甜,則鎖住的是這個類。多線程時余佛,一個線程進入這個方法時迅皇,其他線程就無法進入,處于等待狀態(tài)衙熔,鎖釋放后才能進入。這樣能確保多個線程同時只有一個線程能初始化對象搅荞。

在第10行打上斷點红氯,再次調(diào)試,當一個線程進入后咕痛,選擇另一個線程痢甘,會有以下提示。

通過這種同步的方法解決了懶漢模式的線程安全問題茉贡,但是同步鎖本身比較消耗資源塞栅,有加鎖和解鎖的開銷。而且synchronized加載static方法上腔丧,鎖住的是類放椰,范圍比較大,對性能有影響愉粤。

doublecheck

第二種方式是將鎖加在方法內(nèi)部砾医,進行雙重判斷。即便兩個線程同時判斷實例為空衣厘,但接下來只有一個進程會進入鎖如蚜,并在此判斷此時實例是否為空,空則初始化對象影暴。這樣是鎖的范圍縮小错邦,降低synchronized的性能開銷。

雙重校驗懶漢模式

這種寫法看上去很完美型宙,但是仍然存在隱患撬呢,問題是處在第10行和第13行。當一個線程進到第13行時妆兑,new了一個對象倾芝。雖然看上去是一步讨勤,實際上new一個對象經(jīng)歷了3個步驟。
1.分配內(nèi)存給這個對象
2.初始化對象
3.設置lazyDoubleCheckSingleton(instance)指向剛分配的內(nèi)存地址
而第二步和第三步可能會被重排序晨另。即先分配內(nèi)存給對象潭千,再將instanc指向剛分配的地址,此時對象還未初始化完成借尿,另一個進程在第10行進行空判斷的時候判斷l(xiāng)azyDoubleCheckSingleton不為空刨晴,結(jié)果return回去的仍然是空。

java語言規(guī)范中說路翻,所有程序在執(zhí)行java程序時狈癞,必須遵守intra-thread semantics這個規(guī)定,允許哪些保證重排序?qū)τ趩尉€程不會改變程序執(zhí)行結(jié)果的重排序茂契,從而提高執(zhí)行性能蝶桶。

解決重排序帶來的隱患

一種解決辦法是禁止這種重排序,做法就是聲明instance的時候加上volatile關鍵字掉冶。通過volatile和doublecheck的這個方法既兼顧了性能又兼顧了線程安全真竖。對于這個字段的理解可以參考:https://www.cnblogs.com/zhengbin/p/5654805.html

而另一種方法,不禁止重排序厌小,而是基于靜態(tài)內(nèi)部類初始化的解決方案恢共。即StaticInnerClassSingleton的instance是在靜態(tài)內(nèi)部類中被初始化的。而靜態(tài)內(nèi)部類InnerClass本身被加載時jvm會給這個內(nèi)部類上鎖璧亚,而staticInnerClassSingleton在初始化賦值的過程中即使發(fā)生重排序讨韭,其他線程也無法獲取實例。只有InnerClass被加載完成后癣蟋,其他線程才能訪問透硝。這種方式實現(xiàn)了延遲加載,降低創(chuàng)建實例帶來的開銷疯搅,也能兼顧線程安全蹬铺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秉撇,隨后出現(xiàn)的幾起案子甜攀,更是在濱河造成了極大的恐慌,老刑警劉巖琐馆,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件规阀,死亡現(xiàn)場離奇詭異,居然都是意外死亡瘦麸,警方通過查閱死者的電腦和手機谁撼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厉碟,你說我怎么就攤上這事喊巍。” “怎么了箍鼓?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵崭参,是天一觀的道長。 經(jīng)常有香客問我款咖,道長何暮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任铐殃,我火速辦了婚禮海洼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘富腊。我一直安慰自己坏逢,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布赘被。 她就那樣靜靜地躺著是整,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帘腹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天许饿,我揣著相機與錄音阳欲,去河邊找鬼。 笑死陋率,一個胖子當著我的面吹牛球化,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瓦糟,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼筒愚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了菩浙?” 一聲冷哼從身側(cè)響起巢掺,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劲蜻,沒想到半個月后陆淀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡先嬉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年轧苫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疫蔓。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡含懊,死狀恐怖身冬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岔乔,我是刑警寧澤酥筝,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站重罪,受9級特大地震影響樱哼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剿配,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一搅幅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呼胚,春花似錦茄唐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至年扩,卻和暖如春蚁廓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厨幻。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工相嵌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人况脆。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓饭宾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親格了。 傳聞我的和親對象是個殘疾皇子看铆,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,392評論 8 265
  • 單例模式(SingletonPattern)一般被認為是最簡單、最易理解的設計模式盛末,也因為它的簡潔易懂弹惦,是項目中最...
    成熱了閱讀 4,253評論 4 34
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,103評論 1 32
  • 設計模式概述 在學習面向?qū)ο笃叽笤O計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上悄但,這兩者...
    彥幀閱讀 3,747評論 0 14
  • 我的第一次戀愛算墨,只有一個月籽懦。 他是我一個朋友介紹的缕溉,比我大四歲茅特,高高瘦瘦的漾唉,戴個眼鏡,一起工作的同事說他挺斯文的。...
    陽秋閱讀 279評論 0 2