實(shí)現(xiàn)Singleton模式

題目:設(shè)計(jì)一個(gè)類畦浓,我們只能生成該類的一個(gè)實(shí)例
題目其實(shí)說(shuō)到底只是常見(jiàn)的單例模式蜜猾,相信大家對(duì)這個(gè)最基礎(chǔ)的設(shè)計(jì)模式早已有所了解傀蚌。

解法一(不好浩姥,只適用于單線程環(huán)境)

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

這里所寫(xiě)的是一個(gè)典型的懶漢式單例散罕,還有一種餓漢式的單例模式分歇,會(huì)在下面介紹。這種寫(xiě)法之所以不好就是因?yàn)樗荒茉诙嗑€程的環(huán)境下使用欧漱。試想一下职抡,此時(shí)有兩個(gè)線程:線程1和線程2,其中線程1執(zhí)行到了if (instance == null)這條語(yǔ)句误甚,這個(gè)時(shí)候線程2如果搶到執(zhí)行權(quán)并且一直執(zhí)行下去缚甩,線程1也就不得不一直等待。當(dāng)線程2執(zhí)行完畢并且返回了一個(gè)Singleton對(duì)象后線程1便開(kāi)始從instance = new Singleton();這條語(yǔ)句開(kāi)始執(zhí)行窑邦,于是在線程2創(chuàng)建了一個(gè)對(duì)象之后擅威,線程1也創(chuàng)建了一個(gè)對(duì)象。因此冈钦,想要只創(chuàng)建一個(gè)對(duì)象的要求在這里是無(wú)法實(shí)現(xiàn)的郊丛。

解法二(雖然在多線程環(huán)境中能夠工作但是效率不高)

解法一的失敗之處主要是由于沒(méi)有考慮多線程的情況,而對(duì)于這種情況最直接的解決方法就是在會(huì)出現(xiàn)問(wèn)題的地方加上一個(gè)同步代碼快瞧筛。

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

現(xiàn)在這個(gè)代碼已經(jīng)可以保證在多線程的情況下只會(huì)創(chuàng)建唯一的一個(gè)實(shí)例厉熟,成功地解決了我們?cè)诮夥ㄒ恢杏龅降膯?wèn)題。但是上鎖是一個(gè)對(duì)于程序來(lái)說(shuō)很耗時(shí)的操作较幌。而我們發(fā)現(xiàn)在這段代碼中無(wú)論什么情況下揍瑟,當(dāng)任何一個(gè)線程想要?jiǎng)?chuàng)建一個(gè)Singleton對(duì)象的時(shí)候都要上一次鎖。毫無(wú)疑問(wèn)乍炉,這大大地降低了程序的運(yùn)行效率绢片,因此還需改進(jìn)嘁字。

解法三(加同步鎖前后兩次判斷實(shí)例是否已經(jīng)存在)

對(duì)解法二中代碼的分析我們發(fā)現(xiàn),事實(shí)上以下代碼只在實(shí)例還沒(méi)有創(chuàng)建的時(shí)候執(zhí)行就行了杉畜。

synchronized (Singleton.class) { 
  if (instance == null) { 
    instance = new Singleton(); 
  } 
} 

于是為了避免在實(shí)例已經(jīng)創(chuàng)建的情況下纪蜒,某一線程想要獲取實(shí)例的時(shí)候仍然會(huì)去執(zhí)行這段同步代碼塊我們有了解法三。

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

上面這段代碼在解法二的同步代碼塊之外又加上了一個(gè)對(duì)于實(shí)例是否已經(jīng)存在的判斷此叠。通過(guò)這種方法纯续,在實(shí)例已經(jīng)創(chuàng)建的情況下,任何線程在執(zhí)行過(guò)程中便不會(huì)再去執(zhí)行同步代碼灭袁,因此在解法二的基礎(chǔ)上大大地提高了程序的運(yùn)行效率猬错。

解法四(餓漢式解決線程問(wèn)題)

解法三看上去雖然已經(jīng)夠用,但是代碼內(nèi)容較長(zhǎng)茸歧。那么倦炒,有沒(méi)有不用同步便能夠?qū)崿F(xiàn)多線程情況下的單例模式的方法呢?餓漢式單例模式就是這個(gè)問(wèn)題的答案软瞎。

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

餓漢式單例模式巧妙地避免了上面三個(gè)解法圍繞的線程安全問(wèn)題逢唤。但是值得注意的是,實(shí)例instance并不是第一次調(diào)用Singleton.getInstance()的時(shí)候創(chuàng)建涤浇,而是程序中第一次用到Singleton的時(shí)候就會(huì)被創(chuàng)建鳖藕。假設(shè)我們?cè)谏厦娴拇a中插入一段與單例要求無(wú)關(guān)的靜態(tài)函數(shù),當(dāng)我們使用這個(gè)靜態(tài)函數(shù)的時(shí)候本是沒(méi)由創(chuàng)建Singleton實(shí)例的只锭,但是餓漢式單例仍然會(huì)為我們過(guò)早地創(chuàng)建實(shí)例著恩,從而降低內(nèi)存的使用效率。

解法五(實(shí)現(xiàn)按需創(chuàng)建實(shí)例)

針對(duì)解法四蜻展,這里的解法五很好地解決了這個(gè)問(wèn)題喉誊。

public class Singleton {
  private Singleton() {}
  public static Singleton getInstance() {
    return Nested.instance;
  }
  
  private static class Nested {
    static Singleton instance = new Singleton();
  }
}

這段代碼中我們?cè)?code>Singleton中定義了一個(gè)私有類型Nested,該類型只有在調(diào)用Singleton.getInstance()的時(shí)候才會(huì)被調(diào)用纵顾。由于我們將Nested定義為private類型伍茄,其他類無(wú)法調(diào)用Nested類型。因此片挂,Singleton實(shí)例只有在任何情況下只有我們調(diào)用Singleton.getInstance()的時(shí)候才會(huì)被創(chuàng)建幻林,最終很好地解決了解法四中的提前創(chuàng)建實(shí)例的問(wèn)題贞盯,真正地做到了按需創(chuàng)建音念。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市躏敢,隨后出現(xiàn)的幾起案子闷愤,更是在濱河造成了極大的恐慌,老刑警劉巖件余,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讥脐,死亡現(xiàn)場(chǎng)離奇詭異遭居,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)旬渠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)俱萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人告丢,你說(shuō)我怎么就攤上這事枪蘑。” “怎么了岖免?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵岳颇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我颅湘,道長(zhǎng)话侧,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任闯参,我火速辦了婚禮瞻鹏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹿寨。我一直安慰自己乙漓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布释移。 她就那樣靜靜地躺著叭披,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玩讳。 梳的紋絲不亂的頭發(fā)上涩蜘,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音熏纯,去河邊找鬼同诫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛樟澜,可吹牛的內(nèi)容都是我干的误窖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼秩贰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼霹俺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起毒费,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤丙唧,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后觅玻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體想际,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡培漏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胡本。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牌柄。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖侧甫,靈堂內(nèi)的尸體忽然破棺而出友鼻,到底是詐尸還是另有隱情,我是刑警寧澤闺骚,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布彩扔,位于F島的核電站,受9級(jí)特大地震影響僻爽,放射性物質(zhì)發(fā)生泄漏虫碉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一胸梆、第九天 我趴在偏房一處隱蔽的房頂上張望敦捧。 院中可真熱鬧,春花似錦碰镜、人聲如沸兢卵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秽荤。三九已至,卻和暖如春柠横,著一層夾襖步出監(jiān)牢的瞬間窃款,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工牍氛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晨继,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓搬俊,卻偏偏與公主長(zhǎng)得像紊扬,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唉擂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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