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

單例模式由于只創(chuàng)建了唯一對象可以避免資源的多重占用采桃,減少內(nèi)存的開銷,對于經(jīng)常性使用對象的類來說丘损,單例是一個不錯的選擇芍碧,使用場景,比如:文件操作号俐、共享資源等等泌豆。

1、餓漢單例模式

這是最為簡單的也是最基本的單例模式吏饿,相信大家都寫過踪危!先上代碼:

public class Single{
   private static final Single instance = new Single();
    private Single(){}
    public static Single getInstance(){
        return instance;
    }
}

由于把構(gòu)造函數(shù)變?yōu)榱藀rivate,所以要想獲得該類的實例需要通過getInstance()猪落,而不是手動去new一個贞远,這僅僅是最為簡單粗暴的單例模式。

2笨忌、懶漢單例模式

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

懶漢單例模式看起來和餓漢單例模式差不多蓝仲,就多了一個 synchronized 關(guān)鍵字,也就是說該模式是同步的方法單例官疲。在 getInstanc()方法中袱结,可以清楚知道不管該類對象是否已經(jīng)實例了(實際上第一次調(diào)用的時候只new了一次),都會進(jìn)行同步途凫,這樣確實每次都同步確實耗費(fèi)了不必要的資源和內(nèi)存垢夹,而且在加載的時候都會事先 synchronized,所以會比較耗時間维费,所以不太建議使用果元。

3、Double Check Lock(DCL)

public class Single{
    
    private static Single instance = null;
    private Single(){}
    public static Single getInstance(){
        if (instance == null){
            synchronized (Single.class){
                if (instance == null){
                    instance = new Single();
                }
            }
        }
        return instance;
    }
}

在代碼中可以看到犀盟,在調(diào)用 getInstance() 方法的時候會檢查類的實例是否為空而晒,true則直接返回該實例,false則會 synchronized (利用Single.class來對本類對象同步)阅畴,如果為null則會new一個對象倡怎,否則直接返回。這意思很清楚,這里有兩次判斷是否為null的步驟诈胜,第一步判斷是為了避免不必要的同步豹障,而第二步則是同步檢查冯事。
??我們知道在new焦匈,即instance = new Single()的時候,一般會有三個步驟:1昵仅、分配內(nèi)存缓熟;2、調(diào)用構(gòu)造函數(shù)并初始化成員字段摔笤;3够滑、為對象指向分配好的空間。而Java是允許處理器亂序執(zhí)行的吕世,還有JDK版本原因彰触,很多時候這三個步驟很可能不是按照順序執(zhí)行的,
所以在多線程的操作下命辖,如果在A線程中執(zhí)行某一步的時候况毅,B線程也調(diào)用了該方法,而這時候A線程剛剛好分配內(nèi)存成功(假設(shè)第一個調(diào)用)但未調(diào)用構(gòu)造函數(shù)創(chuàng)建對象尔艇,所以這時候B在檢查的時候?qū)ο笠呀?jīng)非空了(因為已經(jīng)指向了內(nèi)存)尔许,所以B線程會直接使用對象instance,很顯然终娃,由于還沒調(diào)用構(gòu)造函數(shù)味廊,所以B線程使用的時候會出問題。這叫DCL失效棠耕。雖然說這是很小的概率問題余佛,但還是會長期隱藏著問題的。不過從JDK1.5之后窍荧,sun注意了這個問題衙熔,把這個bug修改了過來,只要 如此聲明:private volatile static Single instance = null 就可以保證instance 是從主內(nèi)存取出來的搅荞,雖然volatile 會影響性能红氯,但為了DCL有效就值得。
??總的來說DCL是餓漢咕痛、懶漢單例模式的結(jié)合痢甘,盡管存在bug,但還是sun已修改了,所以比較建議這種寫法茉贡。

4 塞栅、內(nèi)部靜態(tài)類單例模式

??利用靜態(tài)內(nèi)部類的特性來返回對象(static關(guān)鍵字不用多講了吧)

public class Single {

    private Single (){}
    public static Single getInstance(){
        return SingleHolder.instance;
    }
    private static class SingleHolder{
        private static final Single  instance = new Single();
    }

}

??這不僅僅首次調(diào)用才初始化,而且線程安全腔丧,也能保證對象的唯一性放椰,所以這也是推薦的寫法作烟。

5、枚舉單例模式

public enum  SingleEnum {
    INSTANCE;
}

在Java中砾医,枚舉類型是默認(rèn)線程安全的拿撩,在任何情況下都能保證唯一性,而且寫法最為簡單如蚜。大家可以嘗試一下的

6压恒、容器單例模式

public class SingleCollect {
    private static Map<String, Object> objectMap = new HashMap<>();
    private SingleCollect(){}

    /**
     * 根據(jù)類名把實例通過Map保存起來
     * @param key  類名
     * @param instance  類的實例對象
     */
    public static void registInatance(String key, Object instance){
        if (!objectMap.containsKey(key)){
            objectMap.put(key, instance);
        }
    }

    /**
     * 根據(jù)類名來尋找對應(yīng)的對象實例
     * @param key
     * @return
     */
    public static Object getInstance(String key){
        return objectMap.get(key);
    }
}

??利用Map把類的對象實例保存起來,在需要的時候根據(jù)類名key獲取即可错邦。

總結(jié)

??通過幾種單例模式探赫,核心思想無非是把構(gòu)造函數(shù)私有化,然后利用 public static修飾符來獲取對象實例撬呢,并且保證線程安全B追汀!魂拦!值得注意的時候毛仪,我們還需要考慮這么一種情況:反序列化。我們知道可以通過序列化把對象實例寫進(jìn)磁盤晨另,然后再讀回來潭千。而反序列化依然可以通過別的途徑去重新創(chuàng)建一個新的對象實例,即便是私有的構(gòu)造函數(shù)借尿!上述的幾種模式就只有枚舉單例模式可以避免刨晴。不過,在實際開發(fā)中路翻,我們需要結(jié)合項目需要狈癞,而不是一味地直接使用枚舉單例模式,靈活使用單例模式才是正道茂契。
??上文如有不對或者不妥之處蝶桶,大家記得留言指出哈。一起進(jìn)步才比較爽暗粢薄U媸!厌小!and then 后續(xù)我會繼續(xù)寫一系列關(guān)于設(shè)計模式的恢共,請大家靜候!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末璧亚,一起剝皮案震驚了整個濱河市讨韭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖透硝,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狰闪,死亡現(xiàn)場離奇詭異,居然都是意外死亡濒生,警方通過查閱死者的電腦和手機(jī)埋泵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門享言,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亩歹,“玉大人,你說我怎么就攤上這事」娣В” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵瘦麸,是天一觀的道長谁撼。 經(jīng)常有香客問我,道長滋饲,這世上最難降的妖魔是什么厉碟? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮屠缭,結(jié)果婚禮上箍鼓,老公的妹妹穿的比我還像新娘。我一直安慰自己呵曹,他們只是感情好款咖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奄喂,像睡著了一般铐殃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跨新,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天富腊,我揣著相機(jī)與錄音,去河邊找鬼域帐。 笑死赘被,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肖揣。 我是一名探鬼主播民假,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼许饿!你這毒婦竟也來了阳欲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎球化,沒想到半個月后秽晚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筒愚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年赴蝇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巢掺。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡句伶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陆淀,到底是詐尸還是另有隱情考余,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布轧苫,位于F島的核電站楚堤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏含懊。R本人自食惡果不足惜身冬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岔乔。 院中可真熱鬧酥筝,春花似錦、人聲如沸雏门。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剿配。三九已至搅幅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間呼胚,已是汗流浹背茄唐。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝇更,地道東北人沪编。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像年扩,于是被迫代替她去往敵國和親蚁廓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

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

  • 單例模式(SingletonPattern)一般被認(rèn)為是最簡單厨幻、最易理解的設(shè)計模式相嵌,也因為它的簡潔易懂腿时,是項目中最...
    成熱了閱讀 4,255評論 4 34
  • 概念 java中單例模式是一種常見的設(shè)計模式,單例模式的寫法有好幾種饭宾,比較常見的有:懶漢式單例批糟、餓漢式單例。單例模...
    怡紅快綠閱讀 463評論 0 0
  • Java設(shè)計模式——單例模式 單例模式應(yīng)該是大家最為熟知的一種設(shè)計模式了看铆,相信大家或多或少的都在自己的項目中使用過...
    gogoingmonkey閱讀 515評論 0 2
  • 今天筆試的時候被問到了單例模式,聽了很多次,但是卻沒有認(rèn)真看過,所以交了白卷,懶的教訓(xùn)啊!還有一題比較有趣的題目:...
    shakesbears閱讀 374評論 0 3
  • 閱讀原文 在介紹單例模式之前徽鼎,我們先了解一下,什么是設(shè)計模式弹惦?設(shè)計模式(Design Pattern):是一套被反...
    gyl_coder閱讀 158評論 0 3