Java設(shè)計模式-單例模式

一、什么是單例模式

保證一個類僅有一個實(shí)例,并提供了一個訪問他的全局訪問點(diǎn)嫩舟。其目的是保證整個應(yīng)用中只存在類的唯一實(shí)例。

比如我們在系統(tǒng)啟動時怀偷,需要加載一些公共的配置信息家厌,對整個應(yīng)用程序的整個生命周期中都可見且唯一,這時需要設(shè)計成單例模式椎工。如:Spring容器饭于,session工廠,緩存维蒙,數(shù)據(jù)庫連接池等等掰吕。

二、單例的實(shí)現(xiàn)主要是通過以下兩個步驟:

1颅痊,將該類的構(gòu)造方法定義為私有方法殖熟,這樣其他處的代碼就無法通過調(diào)用該類的構(gòu)造方法來實(shí)例化該類的對象,只有通過該類提供的靜態(tài)方法來得到該類的唯一實(shí)例斑响;

2菱属,在該類內(nèi)提供一個靜態(tài)方法,當(dāng)我們調(diào)用這個方法時舰罚,如果類持有的引用不為空就返回這個引用纽门,如果類保持的引用為空就創(chuàng)建該類的實(shí)例并將實(shí)例的引用賦予該類保持的引。

三营罢、適用場景

1赏陵,需要生成唯一序列的環(huán)境

2,需要頻繁實(shí)例化然后銷毀代碼的對象

3饲漾,有狀態(tài)的工具類對象

4瘟滨,頻繁訪問數(shù)據(jù)庫或文件的對象

以下都是單例模式的經(jīng)典實(shí)用場景

1,資源共享的情況下能颁,避免由于資源操作時導(dǎo)致的性能活損耗。如日志文件倒淫,應(yīng)用配置

2伙菊,控制資源的情況下,方便資源之間的相互通信。如線程池等镜硕。

應(yīng)用場景舉例:

1运翼,外部資源:每臺計算機(jī)有若干個打印機(jī),但是只能有一個PrinterSpooler兴枯,以避免兩個打印作業(yè)同時輸出到打印機(jī)血淌。

內(nèi)部資源:大多數(shù)軟件都有一個或者多個屬性文件存放系統(tǒng)配置,這樣的系統(tǒng)應(yīng)該有一個對象管理這些屬性文件

2财剖,Windows的Task Manager(任務(wù)管理器)就是很典型的單例模式悠夯,我們不能同事打開兩個windows task manager

3,windows的回收站也是典型的單例應(yīng)用躺坟,回收站一直維護(hù)著僅有的一個實(shí)例

4沦补,網(wǎng)站的計數(shù)器,一般也是采用單例模式來實(shí)現(xiàn)咪橙,否則難同步

5夕膀,應(yīng)用程序的日志應(yīng)用,一般都用單例模式美侦,由于共享的日志文件一直處于打開狀態(tài)产舞,因?yàn)橹荒苡幸粋€實(shí)例去操作,否則內(nèi)容不好追加

6菠剩,Web應(yīng)用的配置對象的讀取易猫,一般也應(yīng)用單例模式,這個是由于配置文件是共享資源赠叼。

7擦囊,數(shù)據(jù)庫連接池的設(shè)計一般也是采用單例模式,因?yàn)閿?shù)據(jù)庫連接是一種數(shù)據(jù)庫資源嘴办。數(shù)據(jù)庫軟件系統(tǒng)中使用數(shù)據(jù)庫連接池瞬场,主要是節(jié)省打開或者關(guān)閉數(shù)據(jù)庫連接索引引起的效率損耗,這種效率上的消耗是非常昂貴的涧郊,因?yàn)橛脝卫J絹砭S護(hù)挠羔,就可以大大降低這種損耗。

8笋庄,多線程的線程池的設(shè)計一般也是采用單例模式旷太,這是由于線程池要方便對池中的線程進(jìn)行控制

9,操作系統(tǒng)的文件系統(tǒng)批旺,也是大的單例模式實(shí)現(xiàn)的具體例子幌陕,一個操作系統(tǒng)只能有一個文件系統(tǒng)。

10汽煮,HttpApplication也是單例的典型應(yīng)用搏熄。熟悉ASP.Net(IIS)的整個請求生命周期的人應(yīng)該知道棚唆,HttpApplication也是單例模式,所有的HttpModule都共享一個HttpApplication實(shí)例心例。


四宵凌、如何保證實(shí)例的唯一

1,防止外部初始化

2止后,由類本身進(jìn)行實(shí)例化

3瞎惫,保證實(shí)例化一次

4,對外提供獲取實(shí)例的對象

5译株,線程返券

五瓜喇、單例模式的優(yōu)缺點(diǎn)

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

內(nèi)存中只有一個對象,節(jié)省內(nèi)存空間

避免頻繁的創(chuàng)建銷毀對象古戴,可以提高性能

避免對資源的多重占用欠橘,簡化訪問

為整個系統(tǒng)提供一個全局訪問點(diǎn)

缺點(diǎn):

不適用于變化頻繁的對象;

濫用單利將帶來一些問題现恼,如為了節(jié)省資源將數(shù)據(jù)庫連接池對象設(shè)計為的單利類肃续,可能會導(dǎo)致共享連接池對象的程序過多而出現(xiàn)連接池溢出;

如果實(shí)例化的對象長時間不被利用叉袍,系統(tǒng)會認(rèn)為該對象是垃圾而被回收始锚,這可能會導(dǎo)致對象狀態(tài)的丟失;

六喳逛、單例模式的實(shí)現(xiàn)

1瞧捌,餓漢式

// 餓漢式單例

public class Singleton1 {

? ? // 指向自己實(shí)例的私有靜態(tài)引用,主動創(chuàng)建

? ? private static Singleton1 singleton1 = new Singleton1();

? ? // 私有的構(gòu)造方法

? ? private Singleton1(){}

? ? // 以自己實(shí)例為返回值的靜態(tài)的公有方法润文,靜態(tài)工廠方法

? ? public static Singleton1 getSingleton1(){

? ? ? ? return singleton1;

? ? }

}

我們知道姐呐,類加載的方式是需加載,切加載一次典蝌。曙砂。因此,在上述單例被加載時骏掀,就會實(shí)例化一個對象并交給自己的引用鸠澈,供系統(tǒng)使用;而且截驮,由于來在整個生命周期中只會被加載一次笑陈,因此只會創(chuàng)建一個實(shí)例,即能夠充分保證單例葵袭。

優(yōu)點(diǎn):這種寫法比較簡單涵妥,就是在類裝載的時候就完成實(shí)例化。避免了線程同步問題坡锡。

缺點(diǎn):在類裝載的時候就完成實(shí)例化妹笆,沒有達(dá)到Lazy Loading的效果块请。如果喲偶的類從始至終都未使用過這個實(shí)例,則會造成內(nèi)存浪費(fèi)拳缠。

2,懶漢式

// 懶漢式單例

public class Singleton2 {

? ? // 指向自己實(shí)例的私有靜態(tài)引用

? ? private static Singleton2 singleton2;

? ? // 私有的構(gòu)造方法

? ? private Singleton2(){}

? ? // 以自己實(shí)例為返回值的靜態(tài)的公有方法贸弥,靜態(tài)工廠方法

? ? public static Singleton2 getSingleton2(){

? ? ? ? // 被動創(chuàng)建窟坐,在真正需要使用時才去創(chuàng)建

? ? ? ? if (singleton2 == null) {

? ? ? ? ? ? singleton2 = new Singleton2();

? ? ? ? }

? ? ? ? return singleton2;

? ? }

}

我們從懶漢式單例可以看到,單例實(shí)例被延遲加載绵疲,即只有在真正使用的時候才會實(shí)例化一個對象并交給自己的引用哲鸳。

這種寫法起到了Lazy Loading的效果,但是只能在單線程下使用盔憨。如果多線程下徙菠,一個線程進(jìn)入了if(singletion==null)判斷語句塊,還未來得及往下執(zhí)行郁岩,另一個線程也通過了這個判斷語句婿奔,這時變回產(chǎn)生多個實(shí)例。所以在多線程下不可用這種方式问慎。

3萍摊,接下來對它進(jìn)行線程安全改造

(1)同步鎖

public synchronized static Singleton getInstance() {

if (singleton == null) {

singleton = new Singleton();

}

return singleton;

}

優(yōu)點(diǎn):線程安全

缺點(diǎn):每次獲取實(shí)例都要枷鎖,耗費(fèi)資源如叼,其實(shí)主要實(shí)例已經(jīng)生成冰木,以后獲取就不需要在鎖了。

(2)雙重檢查鎖

public class Singleton

? ? {

? ? ? ? private static Singleton instance;

? ? ? ? //程序運(yùn)行時創(chuàng)建一個靜態(tài)只讀的進(jìn)程輔助對象

? ? ? ? private static readonly object syncRoot = new object();

? ? ? ? private Singleton() { }

? ? ? ? public static Singleton GetInstance()

? ? ? ? { //先判斷是否存在笼恰,不存在再加鎖處理

? ? ? ? ? if (instance == null)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? //在同一個時刻加了鎖的那部分程序只有一個線程可以進(jìn)入

? ? ? ? ? ? ? ? lock (syncRoot)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? if (instance == null)

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? instance = new Singleton();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? return instance;

? ? ? ? }

? ? }


public static Singleton getInstance() {

if (singleton == null) {

synchronized (Singleton.class) {

if (singleton == null) {

singleton = new Singleton();

}

}

}

return singleton;

}

代碼中我們進(jìn)行了兩次if(singletion==null)檢查踊沸,這樣就可以保證線程安全了。這樣社证,實(shí)例化代碼只執(zhí)行一次逼龟,后面再次訪問時,判斷if(singletion==null)直接return實(shí)例化對象猴仑。

使用了雙重檢測同步延遲加載去創(chuàng)建單例的做法是一個非常優(yōu)秀的做法审轮,其不但保證了單例,而且切實(shí)提高了程序運(yùn)行效率

優(yōu)點(diǎn):線程安全辽俗;延遲加載疾渣;效率較高。

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

public class Singleton {

private Singleton() {

}


private static class SingletonHolder {

private static final Singleton singleton = new Singleton();

}


public static Singleton getInstance() {

return SingletonHolder.singleton;

}

}

優(yōu)點(diǎn):既避免了同步帶來的性能損耗崖飘,又能夠延遲加載



https://www.cnblogs.com/jiangkuan/p/6031040.html

https://www.cnblogs.com/lcxdevelop/p/11080895.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榴捡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子朱浴,更是在濱河造成了極大的恐慌吊圾,老刑警劉巖达椰,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異项乒,居然都是意外死亡啰劲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門檀何,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝇裤,“玉大人,你說我怎么就攤上這事频鉴∷ü迹” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵垛孔,是天一觀的道長藕甩。 經(jīng)常有香客問我,道長周荐,這世上最難降的妖魔是什么狭莱? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮羡藐,結(jié)果婚禮上贩毕,老公的妹妹穿的比我還像新娘。我一直安慰自己仆嗦,他們只是感情好辉阶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘩扼,像睡著了一般谆甜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上集绰,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天规辱,我揣著相機(jī)與錄音,去河邊找鬼栽燕。 笑死罕袋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碍岔。 我是一名探鬼主播浴讯,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蔼啦!你這毒婦竟也來了榆纽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奈籽,沒想到半個月后饥侵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衣屏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年躏升,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勾拉。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡煮甥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出藕赞,到底是詐尸還是另有隱情,我是刑警寧澤卖局,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布斧蜕,位于F島的核電站,受9級特大地震影響砚偶,放射性物質(zhì)發(fā)生泄漏批销。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一染坯、第九天 我趴在偏房一處隱蔽的房頂上張望均芽。 院中可真熱鬧,春花似錦单鹿、人聲如沸掀宋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劲妙。三九已至,卻和暖如春儒喊,著一層夾襖步出監(jiān)牢的瞬間镣奋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工怀愧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侨颈,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓芯义,卻偏偏與公主長得像哈垢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子毕贼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

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