Java設(shè)計(jì)模式:單例模式

Java設(shè)計(jì)模式——單例模式

1行拢、餓漢模式

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {
    }
    public static Singleton newInstance() {
        return instance;
    }
}  

將對象構(gòu)建放在了static語句中氮兵,JVM加載類的時候會執(zhí)行靜態(tài)語句和靜態(tài)代碼塊荠耽,而且虛擬機(jī)保證類只被初始化一次眶根,所以類的初始化是單線程執(zhí)行的腥放,所以這種是線程安全的泛啸,缺點(diǎn)就是初始化太早,可能造成空間浪費(fèi)秃症。

2平痰、懶漢模式,延遲加載

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    }
    public static Singleton newInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

在加載類的時候不會進(jìn)行實(shí)例化伍纫,在獲取實(shí)例的話宗雇,如果為空,則進(jìn)行實(shí)例化莹规,單線程不會出問題赔蒲,多線程可能會創(chuàng)建多個實(shí)例,造成不是單例良漱,可以進(jìn)行改進(jìn):

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    }
    public static synchronized Singleton newInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

使用synchronized控制線程同步訪問

3舞虱、雙重校驗(yàn)鎖

上述模式實(shí)現(xiàn)了延遲加載和線程安全,但是由于使用synchronized會造成性能下降母市,因?yàn)橥瑫r只有一個進(jìn)程可以調(diào)用newInstance()方法矾兜,采用雙重校驗(yàn)鎖可以提高性能

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton newInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

synchronized并沒有加在方法上,一般情況下患久,當(dāng)倆個線程執(zhí)行newInstance()方法椅寺,判斷instance都為null時,就會創(chuàng)建倆個不同的實(shí)例蒋失,所以為了解決這個問題返帕,所以在同步代碼塊中還得加入驗(yàn)證instance == null代碼。

這里還有一個問題篙挽,由于Java的指令重排優(yōu)化的存在荆萤,instance = new Singleton()語句不具有原子性,他是分幾步執(zhí)行的:

1.給對象分配內(nèi)存空間
2.在內(nèi)存空間創(chuàng)建對象
3.將對象引用賦值給instance

2必須在1之后執(zhí)行铣卡,但是3和2之間沒有依賴關(guān)系链韭,程序執(zhí)行的時候順序可以是1->2->3,也可能是1->3->2

如果是單線程程序煮落,無論執(zhí)行的順序是什么敞峭,使用instances的時候,虛擬機(jī)可以保證它是初始化完成的

如果是多線程程序州邢,一個線程在執(zhí)行instance = new Singleton()的時候儡陨,其他的線程是要執(zhí)行第一個if (instance == null)語句的褪子,因?yàn)檫@個語句在同步鎖的外面,這個時候就涉及到執(zhí)行順序:
如果按1->2->3執(zhí)行骗村,在執(zhí)行3之前嫌褪,instance的引用一直都是null,如果這時候第二個線程執(zhí)行newInstance()方法胚股,就會一直在同步代碼塊外面等待笼痛,直到同步代碼塊執(zhí)行完3后,第二個線程進(jìn)入琅拌,判斷instance不為空缨伊,然后執(zhí)行return語句,返回的是第一個線程初始化的對象进宝,這是正確的刻坊。
如果按1->3->2執(zhí)行,執(zhí)行完3但是還沒有執(zhí)行2的時候党晋,第二個線程執(zhí)行newInstance()方法谭胚,由于現(xiàn)在的instance已經(jīng)有了引用對象,不是null未玻,所有第二個線程不會在同步代碼塊外面等待灾而,會直接執(zhí)行return語句,此時返回的instance還沒有完成初始化扳剿,是錯誤的對象旁趟。

上面的問題就是因?yàn)镴VM的自動優(yōu)化操作,可以使用volatile禁止指令重排優(yōu)化庇绽,也就是保證先分配空間锡搜,然后賦值引用,代碼如下:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    public static Singleton newInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

4敛劝、靜態(tài)內(nèi)部類

public class Singleton {
    
    private static class SingletonHolder {
        public static Singleton instance = new Singleton();
    }
    
    private Singleton() {}
    
    public static Singleton newInstance() {
        return SingletonHolder.instance;
    }
    
}

不會在一開始就加載靜態(tài)內(nèi)部類SingletonHolder余爆,其他地方使用SingletonHolder的時候才會加載,比如第一次調(diào)用newInstance()方法夸盟,從而實(shí)現(xiàn)了延遲加載。和餓漢模式一樣像捶,也利用了類加載機(jī)制上陕,所以可以保證線程安全。

5拓春、枚舉

public enum Singleton {
    INSTANCE;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末释簿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子硼莽,更是在濱河造成了極大的恐慌庶溶,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異偏螺,居然都是意外死亡行疏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門套像,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酿联,“玉大人,你說我怎么就攤上這事夺巩≌耆茫” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵柳譬,是天一觀的道長喳张。 經(jīng)常有香客問我,道長美澳,這世上最難降的妖魔是什么蹲姐? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮人柿,結(jié)果婚禮上柴墩,老公的妹妹穿的比我還像新娘。我一直安慰自己凫岖,他們只是感情好江咳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哥放,像睡著了一般歼指。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甥雕,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天踩身,我揣著相機(jī)與錄音,去河邊找鬼社露。 笑死挟阻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的峭弟。 我是一名探鬼主播附鸽,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瞒瘸!你這毒婦竟也來了坷备?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤情臭,失蹤者是張志新(化名)和其女友劉穎省撑,沒想到半個月后赌蔑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡竟秫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年娃惯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸿摇。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡石景,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拙吉,到底是詐尸還是另有隱情潮孽,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布筷黔,位于F島的核電站往史,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏佛舱。R本人自食惡果不足惜椎例,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望请祖。 院中可真熱鬧订歪,春花似錦、人聲如沸肆捕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慎陵。三九已至眼虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間席纽,已是汗流浹背捏悬。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留润梯,地道東北人过牙。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像仆救,于是被迫代替她去往敵國和親抒和。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359