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

什么是單例模式记某?

單例模式,是一種常用的軟件設(shè)計(jì)模式构捡,屬于對(duì)象創(chuàng)建模式的一種液南。在應(yīng)用這個(gè)模式時(shí),單例對(duì)象的類(lèi)必須保證只有一個(gè)實(shí)例存在勾徽。

單例模式的使用場(chǎng)景滑凉?

  • 系統(tǒng)關(guān)鍵組件,需要保證系統(tǒng)中只有一個(gè)實(shí)例;
  • 類(lèi)的初始化需要消耗較多的系統(tǒng)資源畅姊;

如何實(shí)現(xiàn)咒钟?

  • 私有的構(gòu)造函數(shù)。杜絕外部通過(guò)構(gòu)造方法顯式創(chuàng)建類(lèi)的實(shí)例若未,確保系統(tǒng)中僅有一個(gè)實(shí)例的存在朱嘴;
  • 提供單例實(shí)例的全局訪(fǎng)問(wèn)點(diǎn)。一般為 Method namegetInstance() 的靜態(tài)方法粗合,返回結(jié)果為單例實(shí)例萍嬉;
  • 獲取單例實(shí)例時(shí),首先判斷虛擬機(jī)中實(shí)例是否已存在隙疚,如果有則返回壤追,如果沒(méi)有則創(chuàng)建;

常見(jiàn)寫(xiě)法及分析

單例模式雖然簡(jiǎn)單供屉,實(shí)現(xiàn)方式卻比孔乙己老先生的茴字寫(xiě)法還要多行冰。以下:

餓漢模式

/**
 * 單例(饑餓模式):靜態(tài)變量初始化保證線(xiàn)程安全
 */
public final class HungerSingleton {

    /**
     * 私有構(gòu)造方法,保證不能通過(guò) new 創(chuàng)建新的實(shí)例
     */
    private HungerSingleton(){}

    /**
     * 靜態(tài)示例變量
     */
    private static final HungerSingleton INSTANCE = new HungerSingleton();

    /**
     * 獲取類(lèi)的單例實(shí)例
     *
     * @return
     */
    public static HungerSingleton getInstance(){
        return INSTANCE;
    }
}

餓漢模式是最常用的單例寫(xiě)法贯卦,JDK 中的 java.lang.Runtime 就是這樣實(shí)現(xiàn)的资柔,基于 classloader 機(jī)制,這種寫(xiě)法可以避免多線(xiàn)程的同步問(wèn)題撵割;不過(guò) instance 在類(lèi)裝載的時(shí)候就實(shí)例化贿堰,容易產(chǎn)生垃圾對(duì)象,對(duì)于基礎(chǔ)服務(wù)中的非核心模塊啡彬,不建議使用餓漢模式羹与,而應(yīng)該使用懶加載的單例寫(xiě)法-“按需創(chuàng)建”。

Synchronized 版(懶漢式)

/**
 * 同步版本的單例
 * 1 懶加載
 * 2 使用 Synchronized 關(guān)鍵字來(lái)實(shí)現(xiàn)互斥
 * 3 最常見(jiàn)的懶漢版本
 */
public final class SynchronizedSingleton {
    private static SynchronizedSingleton instance;

    private SynchronizedSingleton() {
        if (instance != null) {
            throw new IllegalStateException("單例實(shí)例已經(jīng)初始化");
        }
    }

    public static synchronized SynchronizedSingleton getInstance() {
        if (instance == null) {
            instance = new SynchronizedSingleton();
        }
        return instance;
    }
}

同步版本的單例實(shí)現(xiàn)了懶加載庶灿,在多線(xiàn)程環(huán)境中也可以很好的工作纵搁,但是,效率很低往踢,因?yàn)槎鄶?shù)情況下都不需要同步剥汤。雙重檢查鎖版本是對(duì) Synchronized 版本的改進(jìn)气堕。

雙重檢查鎖版(懶漢式)

/**
 * 雙重檢查鎖單例
 * 1 懶加載铆惑;
 * 2 線(xiàn)程安全(通過(guò)鎖機(jī)制來(lái)保證)
 * 相比 Synchronized 的寫(xiě)法會(huì)有性能上的提升掏颊,主要體現(xiàn)在不會(huì)每次獲取實(shí)例都獲取鎖(只有在實(shí)例沒(méi)有初始化的情況下,才會(huì)獲取鎖)瘦癌;
 */
public final class DoubleCheckLockingSingleton {

    private static volatile DoubleCheckLockingSingleton instance;

    /**
     * 私有構(gòu)造方法
     */
    private DoubleCheckLockingSingleton(){
        // 判斷單例是否已經(jīng)初始化猪贪,來(lái)組織反射創(chuàng)建單例
        if (instance != null) {
            throw new IllegalStateException("單例對(duì)象已經(jīng)初始化");
        }
    }

    /**
     * 單例方法
     *
     * @return
     */
    public static DoubleCheckLockingSingleton getInstance(){
        // 局部變量提升 25% 的性能?存疑 TODO 待考證
        DoubleCheckLockingSingleton result = instance;
        if (result == null) {
            synchronized (DoubleCheckLockingSingleton.class) {
                result = instance;
                if (result == null) {
                    instance = result = new DoubleCheckLockingSingleton();
                }
            }
        }
        return result;
    }

}

這種方式是懶加載常用的寫(xiě)法讯私,在多線(xiàn)程環(huán)境中也可以保證單例的正確創(chuàng)建热押,getInstance 方法執(zhí)行效率比 Synchronized 版本要高西傀。

靜態(tài)內(nèi)部類(lèi)版(懶漢式)

/**
 * 靜態(tài)內(nèi)部類(lèi)延遲加載單例
 */
public final class OnDemandHolderSingleton {

    /**
     * 私有構(gòu)造方法
     */
    private OnDemandHolderSingleton(){}

    /**
     * 獲取單例實(shí)例
     *
     * @return
     */
    public static OnDemandHolderSingleton getInstance() {
        return SingletonHolder.instance;
    }

    /**
     * 靜態(tài)內(nèi)部類(lèi)
     */
    private static class SingletonHolder {
        private static final OnDemandHolderSingleton instance = new OnDemandHolderSingleton();
    }
}

《Java并發(fā)編程實(shí)踐》中推薦的單例寫(xiě)法,實(shí)現(xiàn)相比雙重檢查鎖簡(jiǎn)單桶癣。適用于對(duì)靜態(tài)域的延遲初始化拥褂;這種方式同樣利用了 classLoader機(jī)制來(lái)保證 instance 初始化時(shí)的線(xiàn)程安全。內(nèi)部類(lèi) SingletonHolder 只有在 OnDemandHolderSingleton.getInstance() 方法調(diào)用時(shí)牙寞,才會(huì)執(zhí)行類(lèi)加載肿仑,進(jìn)而觸發(fā) instance 的創(chuàng)建。

枚舉

/**
 * 枚舉 : 枚舉也是一種單例碎税。
 */
public enum EnumSingleton {
    INSTANCE;
}

天生單例;不過(guò)這種寫(xiě)法很少見(jiàn)馏锡;

參考鏈接

碼云項(xiàng)目鏈接:https://gitee.com/maolv/java_code_example/tree/master/design_pattern/src/main/java/com/gitee/maolv/java/pattern/singleton

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雷蹂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杯道,更是在濱河造成了極大的恐慌匪煌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件党巾,死亡現(xiàn)場(chǎng)離奇詭異萎庭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)齿拂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)驳规,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人署海,你說(shuō)我怎么就攤上這事吗购。” “怎么了砸狞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵捻勉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我刀森,道長(zhǎng)踱启,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任研底,我火速辦了婚禮埠偿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘飘哨。我一直安慰自己胚想,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布芽隆。 她就那樣靜靜地躺著浊服,像睡著了一般统屈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牙躺,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天愁憔,我揣著相機(jī)與錄音,去河邊找鬼孽拷。 笑死吨掌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脓恕。 我是一名探鬼主播膜宋,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼炼幔!你這毒婦竟也來(lái)了秋茫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乃秀,失蹤者是張志新(化名)和其女友劉穎肛著,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跺讯,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枢贿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刀脏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片局荚。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖火本,靈堂內(nèi)的尸體忽然破棺而出危队,到底是詐尸還是另有隱情,我是刑警寧澤钙畔,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布茫陆,位于F島的核電站,受9級(jí)特大地震影響擎析,放射性物質(zhì)發(fā)生泄漏簿盅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一揍魂、第九天 我趴在偏房一處隱蔽的房頂上張望桨醋。 院中可真熱鬧,春花似錦现斋、人聲如沸喜最。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞬内。三九已至迷雪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虫蝶,已是汗流浹背章咧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留能真,地道東北人赁严。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像粉铐,于是被迫代替她去往敵國(guó)和親疼约。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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