單例模式

01?背景

????以我們常用辦公軟件WPS為例,我們使用的時(shí)候期望點(diǎn)擊一次工具欄彈出一個(gè)對(duì)話框初厚,再次點(diǎn)擊的時(shí)候仍然是當(dāng)前對(duì)話框忆谓,而不是出現(xiàn)多個(gè)對(duì)話框。反映到編程中秋泳,其實(shí)就是對(duì)話框只被實(shí)例化一次潦闲,這就是單例模式的一個(gè)應(yīng)用場(chǎng)景。

02?概述

????單例模式(Singleton Pattern):?jiǎn)卫J酱_保某一個(gè)類(lèi)只有一個(gè)實(shí)例迫皱,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例歉闰,這個(gè)類(lèi)稱(chēng)為單例類(lèi),它提供全局訪問(wèn)的方法。

????根據(jù)定義可知單例模式的要點(diǎn)有三個(gè):

??? 1和敬、某個(gè)類(lèi)只能有一個(gè)實(shí)例凹炸;

????2、它必須自行創(chuàng)建這個(gè)實(shí)例昼弟;

??? 3啤它、它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。

????單例模式是一種對(duì)象創(chuàng)建型模式舱痘。單例模式又名單件模式或單態(tài)模式变骡。

03?實(shí)現(xiàn)

3.1 餓漢式

????餓漢法就是在第一次引用該類(lèi)的時(shí)候就創(chuàng)建對(duì)象實(shí)例,而不管實(shí)際是否需要?jiǎng)?chuàng)建衰粹。一上來(lái)就先實(shí)例化锣光,但若類(lèi)沒(méi)有使用的話笆怠,就有點(diǎn)浪費(fèi)資源類(lèi)铝耻。

? ??優(yōu)點(diǎn):這樣做的好處是編寫(xiě)簡(jiǎn)單,無(wú)需關(guān)注線程安全問(wèn)題蹬刷。

? ??缺點(diǎn):

????1瓢捉、會(huì)生產(chǎn)出過(guò)多的實(shí)例對(duì)象,無(wú)論你是否要使用他們办成。

????2泡态、無(wú)法做到延遲創(chuàng)建對(duì)象,但是我們很多時(shí)候都希望對(duì)象可以盡可能地延遲加載迂卢,從而減小負(fù)載某弦,所以需要懶漢法。

3.2?懶漢式

????餓漢式(又稱(chēng)飽漢模式)而克,很飽不著急靶壮,延遲加載,啥時(shí)候用啥時(shí)候創(chuàng)建實(shí)例员萍,存在線程安全問(wèn)題腾降。

????實(shí)例在開(kāi)始時(shí)為空,第一次加載后才實(shí)例化碎绎◇θ溃可節(jié)約一些資源,但在并發(fā)時(shí)有可能出現(xiàn)多個(gè)單例筋帖。

? ??優(yōu)點(diǎn):延時(shí)加載奸晴,用的時(shí)候才會(huì)生產(chǎn)對(duì)象。

? ??缺點(diǎn):存在線程安全問(wèn)題日麸,需要保證同步蚁滋,付出效率的代價(jià)。

? ??1、單線程實(shí)現(xiàn)

????這種寫(xiě)法是最簡(jiǎn)單的辕录,由私有構(gòu)造器和一個(gè)公有靜態(tài)工廠方法構(gòu)成睦霎,在工廠方法中對(duì)singleton進(jìn)行null判斷,如果是null就new一個(gè)出來(lái)走诞,最后返回singleton對(duì)象副女。

? ??優(yōu)點(diǎn):延遲加載,資源利用率高蚣旱,不執(zhí)行g(shù)etInstance()就不會(huì)被實(shí)例化碑幅,可以執(zhí)行該類(lèi)的其他靜態(tài)方法。

? ??缺點(diǎn):第一次加載時(shí)不夠快塞绿,線程不安全沟涨,多線程使用不必要的同步開(kāi)銷(xiāo)大。

? ??2异吻、多線程實(shí)現(xiàn)

? ??1)直接加鎖

? ??優(yōu)點(diǎn):線程安全裹赴。

? ??缺點(diǎn):代價(jià)太高(整個(gè)判空和申請(qǐng)階段全部都加鎖,一勞永逸诀浪,但是效率低棋返,鎖范圍太大)。

? ??2)雙檢查鎖

????雙重鎖模式雷猪,是飽漢模式的優(yōu)化睛竣,進(jìn)行雙重判斷,當(dāng)已經(jīng)創(chuàng)建過(guò)實(shí)例對(duì)象后就無(wú)需加鎖求摇,提高效率射沟。也是一種推薦使用的方式。

????只有對(duì)象為空的時(shí)候才加鎖与境,加完鎖后再判空验夯,防止在加鎖的過(guò)程中被另一個(gè)線程調(diào)用new,即進(jìn)行雙檢查:第一次檢查是避免代價(jià)過(guò)高的問(wèn)題嚷辅,第二次檢查是防止多線程問(wèn)題簿姨。

????注:可以看出來(lái)與直接加鎖相比,鎖的范圍縮小了簸搞,效率得以提升扁位,同時(shí)通過(guò)在申請(qǐng)實(shí)例前加鎖保證線程安全。

? ??優(yōu)點(diǎn):比直接加鎖效率高趁俊。

? ??缺點(diǎn):內(nèi)存讀寫(xiě)reorder不安全域仇。

????reorder問(wèn)題:一般new的執(zhí)行過(guò)程認(rèn)為是分配內(nèi)存->構(gòu)造函數(shù)初始化->返回地址,但是實(shí)際上可能是分配內(nèi)存->返回地址->構(gòu)造函數(shù)這種錯(cuò)亂的順序寺擂。如果線程1reorder暇务,另外一個(gè)線程2判斷非空直接返回pSingleton泼掠,但是這個(gè)對(duì)象實(shí)例是無(wú)法正常使用的,它只是一個(gè)還未調(diào)用構(gòu)造函數(shù)初始化的內(nèi)存垦细。

????所以編譯器需要解決這類(lèi)問(wèn)題择镇,即編譯器不能優(yōu)化。

????3)volatile

??? volatile這個(gè)關(guān)鍵字有兩層語(yǔ)義:

????第一層語(yǔ)義是可見(jiàn)性括改∧逋悖可見(jiàn)性指的是在一個(gè)線程中對(duì)該變量的修改會(huì)馬上由工作內(nèi)存(Work Memory)寫(xiě)回主內(nèi)存(Main Memory),所以會(huì)馬上反應(yīng)在其它線程的讀取操作中嘱能,即看到的都是最新的結(jié)果吝梅。

????第二層語(yǔ)義是禁止指令重排序優(yōu)化。我們寫(xiě)的代碼(尤其是多線程代碼)惹骂,由于編譯器優(yōu)化苏携,在實(shí)際執(zhí)行的時(shí)候可能與我們編寫(xiě)的順序不同。

3.3 靜態(tài)內(nèi)部類(lèi)

????有沒(méi)有一種延時(shí)加載对粪,并且能保證線程安全的簡(jiǎn)單寫(xiě)法呢右冻?我們可以把Singleton實(shí)例放到一個(gè)靜態(tài)內(nèi)部類(lèi)中,這樣就避免了靜態(tài)實(shí)例在Singleton類(lèi)加載的時(shí)候就創(chuàng)建對(duì)象衩侥,并且由于靜態(tài)內(nèi)部類(lèi)只會(huì)被加載一次国旷,所以這種寫(xiě)法也是線程安全的:

3.4 選擇

????一般采用餓漢式矛物,若對(duì)資源十分在意可以采用靜態(tài)內(nèi)部類(lèi)茫死,不建議采用懶漢式及雙重檢測(cè)。

04?特點(diǎn)

4.1 優(yōu)點(diǎn)

????1履羞、提供了對(duì)唯一實(shí)例的受控訪問(wèn)峦萎。因?yàn)閱卫?lèi)封裝了它的唯一實(shí)例,所以它可以嚴(yán)格控制客戶(hù)怎樣以及何時(shí)訪問(wèn)它忆首。

????2爱榔、只存在一個(gè)對(duì)象,節(jié)約系統(tǒng)資源糙及,對(duì)于一些需要頻繁創(chuàng)建和銷(xiāo)毀的對(duì)象详幽,單例模式無(wú)疑可以提高系統(tǒng)的性能。

4.2 缺點(diǎn)

????1浸锨、由于單例模式中沒(méi)有抽象層唇聘,因此單例類(lèi)的擴(kuò)展有很大的困難。

????2柱搜、單例類(lèi)的職責(zé)過(guò)重迟郎,在一定程度上違背了“單一職責(zé)原則”。因?yàn)閱卫?lèi)既充當(dāng)了工廠角色聪蘸,提供了工廠方法宪肖,同時(shí)又充當(dāng)了產(chǎn)品角色表制,包含一些業(yè)務(wù)方法,將產(chǎn)品的創(chuàng)建和產(chǎn)品的本身的功能融合到一起控乾。

? ? 3么介、濫用單例將帶來(lái)一些負(fù)面問(wèn)題。現(xiàn)在很多面向?qū)ο笳Z(yǔ)言(如Java)的運(yùn)行環(huán)境都提供了自動(dòng)垃圾回收的技術(shù)蜕衡,因此夭拌,如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為它是垃圾衷咽,會(huì)自動(dòng)銷(xiāo)毀并回收資源鸽扁,下次利用時(shí)又將重新實(shí)例化,這將導(dǎo)致對(duì)象狀態(tài)的丟失镶骗。

05?應(yīng)用場(chǎng)景

????在以下情況下可以使用單例模式:

? ? 1桶现、系統(tǒng)只需要一個(gè)實(shí)例對(duì)象(線程池、緩存鼎姊、硬件設(shè)備等)骡和,或者需要考慮資源消耗太大而只允許創(chuàng)建一個(gè)對(duì)象。

? ? 2相寇、客戶(hù)調(diào)用類(lèi)的單個(gè)實(shí)例只允許使用一個(gè)公共訪問(wèn)點(diǎn)慰于,除了該公共訪問(wèn)點(diǎn),不能通過(guò)其他途徑訪問(wèn)該實(shí)例唤衫。

? ? 3婆赠、一個(gè)具有自動(dòng)編號(hào)主鍵的表可以有多個(gè)用戶(hù)同時(shí)使用,但數(shù)據(jù)庫(kù)中只能有一個(gè)地方分配下一個(gè)主鍵編號(hào)佳励,否則會(huì)出現(xiàn)主鍵重復(fù)休里,因此該主鍵編號(hào)生成器必須具備唯一性,可以通過(guò)單例模式來(lái)實(shí)現(xiàn)赃承。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妙黍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞧剖,更是在濱河造成了極大的恐慌拭嫁,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抓于,死亡現(xiàn)場(chǎng)離奇詭異做粤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)毡咏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)驮宴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人呕缭,你說(shuō)我怎么就攤上這事堵泽⌒藜海” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵迎罗,是天一觀的道長(zhǎng)睬愤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)纹安,這世上最難降的妖魔是什么尤辱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮厢岂,結(jié)果婚禮上光督,老公的妹妹穿的比我還像新娘。我一直安慰自己塔粒,他們只是感情好结借,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著卒茬,像睡著了一般船老。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上圃酵,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天柳畔,我揣著相機(jī)與錄音,去河邊找鬼郭赐。 笑死薪韩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的堪置。 我是一名探鬼主播躬存,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼张惹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舀锨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起宛逗,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坎匿,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后雷激,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體替蔬,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年屎暇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了承桥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡根悼,死狀恐怖凶异,靈堂內(nèi)的尸體忽然破棺而出蜀撑,到底是詐尸還是另有隱情,我是刑警寧澤剩彬,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布酷麦,位于F島的核電站,受9級(jí)特大地震影響喉恋,放射性物質(zhì)發(fā)生泄漏沃饶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一轻黑、第九天 我趴在偏房一處隱蔽的房頂上張望糊肤。 院中可真熱鬧,春花似錦氓鄙、人聲如沸轩褐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)把介。三九已至,卻和暖如春蟋座,著一層夾襖步出監(jiān)牢的瞬間拗踢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工向臀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巢墅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓券膀,卻偏偏與公主長(zhǎng)得像君纫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芹彬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • 前言 本文主要參考 那些年蓄髓,我們一起寫(xiě)過(guò)的“單例模式”。 何為單例模式舒帮? 顧名思義会喝,單例模式就是保證一個(gè)類(lèi)僅有一個(gè)...
    tandeneck閱讀 2,515評(píng)論 1 8
  • 1 場(chǎng)景問(wèn)題# 1.1 讀取配置文件的內(nèi)容## 考慮這樣一個(gè)應(yīng)用,讀取配置文件的內(nèi)容玩郊。 很多應(yīng)用項(xiàng)目肢执,都有與應(yīng)用相...
    七寸知架構(gòu)閱讀 6,774評(píng)論 12 68
  • 單例模式(SingletonPattern)一般被認(rèn)為是最簡(jiǎn)單、最易理解的設(shè)計(jì)模式译红,也因?yàn)樗暮?jiǎn)潔易懂预茄,是項(xiàng)目中最...
    成熱了閱讀 4,254評(píng)論 4 34
  • 手寫(xiě)單例模式,特別是雙重檢驗(yàn)鎖以及靜態(tài)內(nèi)部類(lèi)侦厚。 一耻陕、基本概念 什么是單例昵慌?確保一個(gè)類(lèi)只有一個(gè)實(shí)例提供該實(shí)例的全局訪...
    Sbabysbreath閱讀 426評(píng)論 0 0
  • 天跟大家講一個(gè)老生常談的話題,單例模式是最常用到的設(shè)計(jì)模式之一淮蜈,熟悉設(shè)計(jì)模式的朋友對(duì)單例模式都不會(huì)陌生斋攀。網(wǎng)上的文章...
    Java圈子閱讀 475評(píng)論 0 1