單例模式

單例模式

什么是單例模式慌申?單例模式就是只允許生成一個(gè)實(shí)例的類(lèi)。

一般來(lái)說(shuō)厨幻,被創(chuàng)建出的單例類(lèi)的對(duì)象都是由單例類(lèi)本身持有,然后也是由單例類(lèi)本身來(lái)創(chuàng)建况脆,也就是說(shuō)單例類(lèi)的構(gòu)造器必須是私有的。

單例類(lèi)主要用來(lái)解決全局類(lèi)被頻繁的創(chuàng)建和銷(xiāo)毀格了,應(yīng)用場(chǎng)景:上數(shù)據(jù)庫(kù)連接驅(qū)動(dòng)捏雌,數(shù)據(jù)庫(kù)連接池等

懶漢模式

懶漢模式指在單例類(lèi)加載時(shí)不進(jìn)行實(shí)例初始化,當(dāng)需要使用實(shí)例時(shí)才進(jìn)行實(shí)例初始化性湿,獲取對(duì)象較慢满败,類(lèi)加載較快

線程不安全

/**

* @Auther: Lee
* @Date: 2018/6/11 10:26
* @Description: 懶漢模式的單例類(lèi) 線程不安全
  */
public class LazyDemo {
    private LazyDemo() {
        System.out.println("你開(kāi)始了肤频?");
    }
 
    public static LazyDemo lazyDemo = null;

    public static LazyDemo getInstance() {
//因?yàn)橹荒軇?chuàng)建一個(gè)實(shí)例變量所以需要判斷靜態(tài)引用變量是否為null
//當(dāng)多個(gè)線程同時(shí)進(jìn)行到這個(gè)步驟,判定都為null算墨,則都會(huì)生成新的實(shí)例
        if (lazyDemo == null){
            lazyDemo = new LazyDemo();
        }
        return lazyDemo;
    }
}
    

以上就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的單例類(lèi)宵荒,但是上面這種方式在多線程環(huán)境下可能會(huì)出現(xiàn)線程不安全的情況净嘀,
比如:在判斷if (lazyDemo == null)處,如果多個(gè)線程同時(shí)執(zhí)行完這個(gè)判斷挖藏,就是線程A執(zhí)行完這個(gè)判斷要進(jìn)行下一步時(shí)膜眠,跳到了另外的線程溜嗜,這個(gè)時(shí)候另外的線程還是判斷引用的是null,那么這些線程都會(huì)執(zhí)行下一步的生成實(shí)例代碼炸宵,并將應(yīng)用變量指向生成的實(shí)例地址谷扣。這樣的話這個(gè)引用變量引用的就不止一個(gè)示例變量了。

線程安全(synchronized關(guān)鍵字)

解決這個(gè)問(wèn)題就需要用到線程同步關(guān)鍵字synchronized会涎;給getInstance方法加鎖,

/**
* @Auther: Lee
* @Date: 2018/6/11 11:41
* @Description: 方法上加鎖的單例類(lèi)
*/
public class LazyLockDemo {
    private LazyLockDemo() {
        System.out.println("我開(kāi)始了老哥!");
    }
    public static LazyLockDemo LazyLockDemo = null;
//這種方式解決了線程的問(wèn)題蛔溃,但是每次執(zhí)行g(shù)etInstance都需要獲得鎖篱蝇,其他的線程等待 類(lèi)似串行執(zhí)行性能不好
    public static synchronized LazyLockDemo getInstance(){
        if (LazyLockDemo==null){
            LazyLockDemo = new LazyLockDemo();
        }
        return LazyLockDemo;
    }
}

上面這種方式對(duì)獲取對(duì)象的整個(gè)方法加鎖,效率較低

雙重檢查鎖

那么可以將鎖的范圍縮小零截,僅僅在new新的對(duì)象那里使用同步涧衙。

/**
* @Auther: Lee
* @Date: 2018/6/11 11:49
* @Description: 雙重檢查鎖哪工,
*/
public class LazyDoubleLockDemo {
    private LazyDoubleLockDemo() {
    System.out.println("我開(kāi)始了老哥雁比!");
    }
    public static volatile LazyDoubleLockDemo lazyDoubleLockDemo = null;
    public static LazyDoubleLockDemo getInstance(){
        if (lazyDoubleLockDemo == null){
// 在使用構(gòu)造方法生成實(shí)例時(shí)獲得鎖撤嫩,獲得鎖之后再進(jìn)行一次判斷是否有實(shí)例
// 這種方式是減少加鎖的范圍,由于syn關(guān)鍵字是可重入鎖序攘,所以?xún)纱渭渔i性能消耗并不會(huì)太多
// 這種方式在語(yǔ)句轉(zhuǎn)化成計(jì)算機(jī)指令時(shí),還是會(huì)出先線程不安全問(wèn)題丈牢,
            synchronized (LazyDoubleLockDemo.class){
                if (lazyDoubleLockDemo ==null){
                    lazyDoubleLockDemo = new LazyDoubleLockDemo();
                }
            }
        }
        return lazyDoubleLockDemo;
    }
}

可以看到瞄沙,上面靜態(tài)引用變量添加了volatile修飾符修飾朴皆,

因?yàn)榉捍猓@里會(huì)涉及到一個(gè)指令重排序問(wèn)題。

instance = new Singleton2(); 其實(shí)可以分為下面的步驟:
1.申請(qǐng)一塊內(nèi)存空間馏谨;
2.在這塊空間里實(shí)例化對(duì)象;
3.instance的引用指向這塊空間地址钾怔;
指令重排序存在的問(wèn)題是:
對(duì)于以上步驟蒙挑,指令重排序很有可能不是按上面123步驟依次執(zhí)行的。
比如矾利,先執(zhí)行1申請(qǐng)一塊內(nèi)存空間馋袜,然后執(zhí)行3步驟,instance的引用去指向剛剛申請(qǐng)的內(nèi)存空間地址察皇,
那么泽台,當(dāng)它再去執(zhí)行2步驟,判斷instance時(shí)怀酷,由于instance已經(jīng)指向了某一地址,它就不會(huì)再為null了因篇,
因此笔横,也就不會(huì)實(shí)例化對(duì)象了。這就是所謂的指令重排序安全問(wèn)題吹缔。所以厢塘,我們需要在創(chuàng)建引用變量時(shí)加上volatile關(guān)鍵字肌幽,因?yàn)関olatile可以禁止指令重排序抓半。

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

除了上面兩種方式可以解決線程安全問(wèn)題外,還有一種靜態(tài)內(nèi)部類(lèi)的方式

/**

* @Auther: Lee
* @Date: 2018/6/11 11:57
* @Description: 靜態(tài)內(nèi)部類(lèi) 應(yīng)該還是餓漢
  */
public class LazyInnerClassDemo {
    private LazyInnerClassDemo(){
        System.out.println("我開(kāi)始了老哥笛求!");
    }
    private static class InnerClass{
        private static final LazyInnerClassDemo LAZY_DOUBLE_LOCK_DEMO = new LazyInnerClassDemo();
    }
    public static LazyInnerClassDemo getInstance(){
        return InnerClass.LAZY_DOUBLE_LOCK_DEMO;
    }
}

餓漢模式

除了上面幾種懶漢模式的實(shí)現(xiàn)外探入,還有餓漢模式,餓漢模式指的是當(dāng)加載類(lèi)時(shí)就初始化實(shí)例蜂嗽,類(lèi)加載較慢,獲取對(duì)象較快辱揭,與懶漢模式相比隆嗅,餓漢模式是線程安全的

/**
* @Auther: Lee
* @Date: 2018/6/11 14:40
* @Description: 餓漢式單例模式 類(lèi)加載時(shí)就保存一個(gè)實(shí)例對(duì)象
*/
public class HungerDemo {
    private HungerDemo() {
        System.out.println("我好了侯繁,你呢?");
    }

    private static final HungerDemo HUNGER_DEMO = new HungerDemo();

    public static HungerDemo getInstance() {
        return HUNGER_DEMO;
    }
}

枚舉實(shí)現(xiàn)

還有推薦使用的一種:枚舉實(shí)現(xiàn)的單例類(lèi)丽焊, 線程安全咕别,速度很快

/**
* @Auther: Lee
* @Date: 2018/6/12 14:40
* @Description: 使用枚舉實(shí)現(xiàn)單例
*/
public enum EnumDemo {
    INSTANCE;
    EnumDemo(){
        System.out.println("我好了!");
    }
    public void doSomething(){
        System.out.println("我干活了惰拱!");
    }
}

總結(jié):

懶漢模式是時(shí)間換空間,餓漢模式是空間換時(shí)間偿短,
懶漢線程不安全,需要使用線程鎖和雙重檢查實(shí)現(xiàn)線程安全降传,餓漢是線程安全的勾怒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末声旺,一起剝皮案震驚了整個(gè)濱河市段只,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缚够,老刑警劉巖鹦赎,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異雏吭,居然都是意外死亡陪踩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)摘完,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)傻谁,“玉大人,你說(shuō)我怎么就攤上這事谈飒√伲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵手素,是天一觀的道長(zhǎng)瘩蚪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)募舟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任琢锋,我火速辦了婚禮,結(jié)果婚禮上钉嘹,老公的妹妹穿的比我還像新娘鲸阻。我一直安慰自己,他們只是感情好鸟悴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布细诸。 她就那樣靜靜地躺著,像睡著了一般利赋。 火紅的嫁衣襯著肌膚如雪猩系。 梳的紋絲不亂的頭發(fā)上媚送,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天塘偎,我揣著相機(jī)與錄音幽纷,去河邊找鬼博敬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛偏窝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伦意,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驮肉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了离钝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤慧域,失蹤者是張志新(化名)和其女友劉穎浪读,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體互订,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痘拆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年错负,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犹撒。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诚镰,靈堂內(nèi)的尸體忽然破棺而出祥款,到底是詐尸還是另有隱情,我是刑警寧澤刃跛,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布桨昙,位于F島的核電站,受9級(jí)特大地震影響蛙酪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凹蜂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泥彤。 院中可真熱鬧卿啡,春花似錦、人聲如沸颈娜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)同仆。三九已至,卻和暖如春俗批,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辛慰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工干像, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人速客。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓五鲫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親辅愿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忆某,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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

  • 【學(xué)習(xí)難度:★☆☆☆☆阔蛉,使用頻率:★★★★☆】直接出處:?jiǎn)卫J绞崂砗蛯W(xué)習(xí):https://github.com/...
    BruceOuyang閱讀 667評(píng)論 1 2
  • 1 場(chǎng)景問(wèn)題# 1.1 讀取配置文件的內(nèi)容## 考慮這樣一個(gè)應(yīng)用,讀取配置文件的內(nèi)容聋呢。 很多應(yīng)用項(xiàng)目,都有與應(yīng)用相...
    七寸知架構(gòu)閱讀 6,684評(píng)論 12 68
  • 概念 確保某一個(gè)類(lèi)只有一個(gè)實(shí)例通铲,而且自行實(shí)例化器贩,并向整個(gè)系統(tǒng)提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn),這個(gè)類(lèi)稱(chēng)為單例類(lèi)蛹稍。 特性 ...
    野狗子嗷嗷嗷閱讀 543評(píng)論 0 2
  • 概述 單例模式(Singleton Pattern):確保某一個(gè)類(lèi)只有一個(gè)實(shí)例唆姐,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)...
    zfylin閱讀 334評(píng)論 0 0
  • 題目二:“我在澳門(mén)玩了三天兩夜”旅行就是學(xué)會(huì)享受當(dāng)下 題目三:故事:澳門(mén)旅行埋下的伏筆 江凱到公司声功,很快就排出了假...
    夏宇嫣_8335閱讀 470評(píng)論 4 5