詳解Java設(shè)計模式之《單例設(shè)計模式》

單例設(shè)計模式(Singleton Pattern)是Java開發(fā)人員了解設(shè)計模式的第一種蟋软,也是最容易理解的,在平時的工作使用的很頻繁的設(shè)計模式之一捧存!

概念

單例設(shè)計模式(Singleton Pattern) :確保每一個類只有一個實例亏较,而且自行實例化并向整個系統(tǒng)提供這個實例,這個類稱為單例類挖炬,它提供全局訪問的方法,屬于創(chuàng)建型模式贼急。

  • 定義:

    • 私有化該類的構(gòu)造函數(shù)
    • 通過new在本類中創(chuàng)建一個本類對象
    • 定義一個公有的方法茅茂,將在該類中所創(chuàng)建的對象返回
  • 確保對象的唯一性:

    • 不允許其他程序用new對象
    • 在該類中創(chuàng)建對象
    • 對外提供一個可以讓其他程序獲取該對象的方法

    單例實現(xiàn):在單例類的內(nèi)部實現(xiàn)只生成一個實例,同時它提供一個靜態(tài)的getInstance() 工廠方法太抓,讓客戶可以訪問它的唯一實例空闲;為了防止在外部對其實例化,將其構(gòu)造函數(shù)設(shè)計為**私有 走敌;在單例類內(nèi)部定義了一個Singleton類型的靜態(tài) **對象碴倾,作為外部共享的唯一實例。

作用

單例設(shè)計模式主要是為了避免因為創(chuàng)建多個實例造成的資源浪費,且多個實例由于多次調(diào)用容易導(dǎo)致結(jié)果出現(xiàn)錯誤跌榔,而使用單例設(shè)計模式能夠保證整個應(yīng)用中有且只有一個實例异雁。

實現(xiàn)方式

餓漢式

優(yōu)點:在類加載 的時候就完成了實例化,避免了多線程同步問題僧须。

缺點:由于在類加載的時候就實例化了纲刀,所以沒有達(dá)到Lazy Loading(懶加載)的效果,也就是說我沒有用到這個實例担平,但是它也會加載示绊,會造成內(nèi)存的浪費(但是這個浪費可以忽略的)

publice class Singleton{
  //在類加載的時候就創(chuàng)建一個對象
  private static Singleton instance = new Singleton();
  //初始化構(gòu)造器
  private Singleton(){}
  //獲取單例的對象
  public static Singleton getInstance(){
      return instance;
  }  
}

懶漢式

基礎(chǔ)版

優(yōu)點:

缺點:當(dāng)多線程工作的時候,如果有多個線程同時運行到if(instance == null)都判斷為空暂论,那么這兩個線程各自都會創(chuàng)建一個實例面褐,這樣就不是單例了。

public class Singleton{
  //先定義對象的引用
  private static Singleton instance;
  //用作初始化的構(gòu)造器取胎,定義為私有展哭,防止外部的類調(diào)用
  private static Singleton(){};
  public static Singleton getInstance(){
      //如果多個線程在此處,則每個線程都會創(chuàng)建一個實例
      if(instance == null){
          instance =new Singleton();
      }
    return instance;
  }
}

Synchronized版本

優(yōu)點:加上了synchronized關(guān)鍵字后闻蛀,getInstance()方法就會鎖上了匪傍。如果有兩個線程同時執(zhí)行到這個方法是,會有其中一個線程獲得同步鎖循榆,進(jìn)而繼續(xù)執(zhí)行析恢,而另外一個線程需要等待,當(dāng)T1線程執(zhí)行完畢之后秧饮,T2才會執(zhí)行映挂。

缺點:加上了同步鎖之后,會強(qiáng)制除T1以外的所有線程等待盗尸,會嚴(yán)重影響程序的執(zhí)行效率柑船。

雙重檢查版本(Double-Check)

優(yōu)點:在同步鎖的外面在做一次判斷,如果這個線程的實例沒有被創(chuàng)建過泼各,則放入鞍时;如果被創(chuàng)建過,則直接返回它的實例扣蜻。

缺點:使用volatile 關(guān)鍵字會屏蔽Java虛擬機(jī)所做的一些代碼優(yōu)化逆巍,可能導(dǎo)致系統(tǒng)運行效率低。

注意:如果使用雙重檢查鎖來實現(xiàn)懶漢式單例類莽使,需要在靜態(tài)成員變量實例之前增加修飾符volatile锐极,被volatile修飾的成員變量可以確保多個線程都能夠正確處理。

public class Singleton{
  //添加volatile 關(guān)鍵字
  private static volatile  Singleton instance;
  private static Singleton();
  private static Singleton getInstance(){
     //第一次判斷:該線程的實例是否被創(chuàng)建
     if(instance == null){
        //使用同步代碼塊芳肌,由于此方法是靜態(tài)的灵再,所以同步鎖是類名.class
        synchronized(Singleton.class){
           //第二次判斷:為了防止了可能出現(xiàn)的多個實例的情況
           if(instance == null){
               intstance = new Singleton();
            }
        }
     }
     return instance; 
  }
}

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

優(yōu)點:餓漢式單例類不是實現(xiàn)延時加載肋层,不管將來用不用始終占據(jù)內(nèi)存;懶漢式單例類線程安全控制繁瑣翎迁,而且性能受影響栋猖。我們在單例類中增加一個**靜態(tài)內(nèi)部類 **,在該內(nèi)部類中創(chuàng)建單例對象汪榔,再將該單例對象通過getinstance方法返回給外部使用蒲拉。

由于靜態(tài)單例對象沒有作為Singleton的成員變量直接實例化,因此類加載時不會實例化Singleton揍异,第一次調(diào)用getInstance()時將加載內(nèi)部類SingletonHolder全陨,在該內(nèi)部類中定義了一個static類型的變量instance,此時會首先初始化這個變量衷掷,由Java虛擬機(jī)來保證其線程安全性,確保該成員變量只能初始化一次柿菩。

缺點:與編程語言本身的特性相關(guān)戚嗅,很多面向?qū)ο笳Z言不支持IoDH

public class Singleton{
  //靜態(tài)內(nèi)部類
  private static class SingletonHolder{
     private static final Singleton instance = new Singleton();  
  }
  private Singleton(){};
  //內(nèi)部類是在需要被實例化時枢舶,調(diào)用getInstance()方法時懦胞,才會去裝載SingletonHolder類
  public static final Singleton getInstance(){
      return SingletonHolder.instance;
  }
}

枚舉

優(yōu)點:它不僅能避免多線程同步問題,而且還自動支持序列化機(jī)制凉泄,防止反序列化重新創(chuàng)建新的對象躏尉,絕對防止多次序列化。

缺點:不能通過reflection attack來調(diào)用構(gòu)造方法后众。

public enum SingletonEnum{
  //枚舉類型變量
  instance;
  public SingletonEnum(){
  }
  public void whateverMethod(){
  }
}

Java中的單例模式

Java的Runtime對象

在Java語言內(nèi)部胀糜,java.lang.Runtime對象就是一個使用單例模式的例子。在每一個Java程序里面蒂誉,都是唯一的一個Runtime對象教藻,應(yīng)用程序可以與其運行環(huán)境發(fā)生相互作用。

Runtime類提供了一個靜態(tài)工廠方法getRuntime():

public static Runtime getRuntime();

通過調(diào)用此方法右锨,可以獲得Runtime類唯一的一個實例:

Runtime rt = Runtime.getInstance();

單例模式的優(yōu)缺點

優(yōu)點:

  • 單例模式提供了對唯一實例的受控訪問括堤。因為單例類封裝了它的唯一實例,所以它可以嚴(yán)格控制客戶怎樣以及如何訪問它绍移。
  • 由于在系統(tǒng)內(nèi)存中只存在一個對象悄窃,因此可以節(jié)約系統(tǒng)資源,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能蹂窖。
  • 允許可變數(shù)目的實例轧抗。基于單例模式我們可以進(jìn)行擴(kuò)展恼策,使用與單例控制相似的方法來獲得指定個數(shù)的對象實例鸦致,既節(jié)省系統(tǒng)資源潮剪,又解決了單例對象共享過多有損性能的問題。

缺點:

  • 由于單例模式中沒有抽象層分唾,因此單例類的擴(kuò)展有很大的困難抗碰。
  • 單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則”绽乔。因為單例類既充當(dāng)了工廠角色弧蝇,同時又充當(dāng)了產(chǎn)品角色,包含一些業(yè)務(wù)方法折砸,將產(chǎn)品的創(chuàng)建和產(chǎn)品的本身的功能融合到一起看疗。
  • 現(xiàn)在很多面向?qū)ο笳Z言的運行環(huán)境都提供了自動垃圾回收的技術(shù),因此睦授,如果實例化對象長時間不被利用两芳,系統(tǒng)會認(rèn)為它是垃圾,會自動銷毀并回收資源去枷,下次利用時又將重新實例化怖辆,這將導(dǎo)致共享的單例對象狀態(tài)的丟失。

應(yīng)用場景

在一下情況下可以考慮使用單例模式:

  • 系統(tǒng)只需要一個實例對象删顶,如系統(tǒng)要求提供一個唯一的序列號生成器或資源管理器竖螃,或者需要考慮資源消耗太大而只允許創(chuàng)建一個對象逗余。
  • 客戶調(diào)用類的單例實例只允許使用一個公共訪問節(jié)點特咆,除了該公共訪問點,不能通過其他路徑訪問該實例录粱。

參考資料

嘟嘟獨立博客

劉偉技術(shù)博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腻格,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子关摇,更是在濱河造成了極大的恐慌荒叶,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件输虱,死亡現(xiàn)場離奇詭異些楣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宪睹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門愁茁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亭病,你說我怎么就攤上這事鹅很。” “怎么了罪帖?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵促煮,是天一觀的道長邮屁。 經(jīng)常有香客問我,道長菠齿,這世上最難降的妖魔是什么佑吝? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮绳匀,結(jié)果婚禮上芋忿,老公的妹妹穿的比我還像新娘。我一直安慰自己疾棵,他們只是感情好戈钢,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著是尔,像睡著了一般殉了。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拟枚,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天宣渗,我揣著相機(jī)與錄音,去河邊找鬼梨州。 笑死,一個胖子當(dāng)著我的面吹牛田轧,可吹牛的內(nèi)容都是我干的暴匠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼傻粘,長吁一口氣:“原來是場噩夢啊……” “哼每窖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弦悉,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤窒典,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后稽莉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瀑志,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年污秆,在試婚紗的時候發(fā)現(xiàn)自己被綠了劈猪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡良拼,死狀恐怖战得,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庸推,我是刑警寧澤常侦,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布浇冰,位于F島的核電站,受9級特大地震影響聋亡,放射性物質(zhì)發(fā)生泄漏肘习。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一杀捻、第九天 我趴在偏房一處隱蔽的房頂上張望井厌。 院中可真熱鬧,春花似錦致讥、人聲如沸仅仆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墓拜。三九已至,卻和暖如春请契,著一層夾襖步出監(jiān)牢的瞬間咳榜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工爽锥, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留涌韩,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓氯夷,卻偏偏與公主長得像臣樱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腮考,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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