設(shè)計(jì)模式(二)單例模式的七種寫法

面試的時(shí)候忧换,問到許多年輕的Android開發(fā)他所會(huì)的設(shè)計(jì)模式是什么馒胆,基本上都會(huì)提到單例模式热康,但是對(duì)

單例模式也是一知半解,在Android開發(fā)中我們經(jīng)常會(huì)運(yùn)用單例模式载弄,所以我們還是要更了解單例模式才

對(duì)耘拇。

定義:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)宇攻。

單例模式結(jié)構(gòu)圖:

單例模式有多種寫法各有利弊惫叛,現(xiàn)在

我們來看看各種模式寫法。

1. 餓漢模式

public class Singleton {  
     private static 

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

Singleton getInstance() {  
     return instance;  
     }  
 }  

這種方式在類加載時(shí)就完成了

初始化逞刷,所以類加載較慢嘉涌,但獲取對(duì)象的速度快。 這種方式基于類加載機(jī)制避免了多線程的同步問題夸浅,

但是也不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類裝載仑最,這時(shí)候初始化instance顯然沒有達(dá)

到懶加載的效果。

2. 懶漢模式(線程不安全)

public class Singleton {  
      private 

static Singleton instance;  
      private Singleton (){
      }   
      public static 

Singleton getInstance() {  
      if (instance == null) {  
          instance = new 

Singleton();  
      }  
      return instance;  
      }  
 }  

懶漢模式申明了一個(gè)靜態(tài)對(duì)象帆喇,

在用戶第一次調(diào)用時(shí)初始化警医,雖然節(jié)約了資源,但第一次加載時(shí)需要實(shí)例化坯钦,反映稍慢一些预皇,而且在多

線程不能正常工作。

3. 懶漢模式(線程安全)

public class Singleton {  
      private 

static Singleton instance;  
      private Singleton (){
      }
      public static 

synchronized Singleton getInstance() {  
      if (instance == null) {  
          instance = 

new Singleton();  
      }  
      return instance;  
      }  
 }  

這種寫法能夠在多線程中很

好的工作葫笼,但是每次調(diào)用getInstance方法時(shí)都需要進(jìn)行同步深啤,造成不必要的同步開銷,而且大部分時(shí)候

我們是用不到同步的路星,所以不建議用這種模式溯街。

4. 雙重檢查模式 (DCL)

public class 

Singleton {  
      private volatile static Singleton singleton;  
      private Singleton 

(){
      }   
      public static Singleton getInstance() {  
      if (instance== null) {  
  

        synchronized (Singleton.class) {  
          if (instance== null) {  
              

instance= new Singleton();  
          }  
         }  
     }  
     return singleton;  
     } 

 
 }  

這種寫法在getSingleton方法中對(duì)singleton進(jìn)行了兩次判空诱桂,第一次是為了不必要的同步,第

二次是在singleton等于null的情況下才創(chuàng)建實(shí)例呈昔。在這里用到了volatile關(guān)鍵字挥等,不了解volatile關(guān)鍵

字的可以查看Java多線程(三)volatile域這篇文章,在這篇文章我也提到了雙重

檢查模式是正確使用volatile關(guān)鍵字的場景之一堤尾。
在這里使用volatile會(huì)或多或少的影響性能肝劲,但考慮

到程序的正確性,犧牲這點(diǎn)性能還是值得的郭宝。 DCL優(yōu)點(diǎn)是資源利用率高辞槐,第一次執(zhí)行g(shù)etInstance時(shí)單例

對(duì)象才被實(shí)例化,效率高粘室。缺點(diǎn)是第一次加載時(shí)反應(yīng)稍慢一些榄檬,在高并發(fā)環(huán)境下也有一定的缺陷衔统,雖然

發(fā)生的概率很小锦爵。DCL雖然在一定程度解決了資源的消耗和多余的同步沪袭,線程安全等問題枝恋,但是他還是在

某些情況會(huì)出現(xiàn)失效的問題焚碌,也就是DCL失效十电,在《java并發(fā)編程實(shí)踐》一書建議用**靜態(tài)內(nèi)部類單例模

式**來替代DCL。

5. 靜態(tài)內(nèi)部類單例模式

public class Singleton { 
    private Singleton

(){
    }
      public static Singleton getInstance(){  
        return 

SingletonHolder.sInstance;  
    }  
    private static class SingletonHolder {  
        

private static final Singleton sInstance = new Singleton();  
    }  
} 

第一次加載

Singleton類時(shí)并不會(huì)初始化sInstance畏线,只有第一次調(diào)用getInstance方法時(shí)虛擬機(jī)加載

SingletonHolder 并初始化sInstance 蒿叠,這樣不僅能確保線程安全也能保證Singleton類的唯一性市咽,所以

推薦使用靜態(tài)內(nèi)部類單例模式施绎。

6. 枚舉單例

public enum Singleton {  
     INSTANCE;  
    

 public void doSomeThing() {  
     }  
 }  

默認(rèn)枚舉實(shí)例的創(chuàng)建是線程安全的,并且在任何情況

下都是單例孤紧,上述講的幾種單例模式實(shí)現(xiàn)中臭猜,有一種情況下他們會(huì)重新創(chuàng)建對(duì)象蔑歌,那就是反序列化园匹,將

一個(gè)單例實(shí)例對(duì)象寫到磁盤再讀回來,從而獲得了一個(gè)實(shí)例。反序列化操作提供了readResolve方法陷揪,這

個(gè)方法可以讓開發(fā)人員控制對(duì)象的反序列化。在上述的幾個(gè)方法示例中如果要杜絕單例對(duì)象被反序列化

是重新生成對(duì)象趁舀,就必須加入如下方法:

private Object readResolve() throws 

ObjectStreamException{
return singleton;
}

枚舉單例的優(yōu)點(diǎn)就是簡單巡蘸,但是大部分應(yīng)用開發(fā)很少用

枚舉擂送,可讀性并不是很高搬味,不建議用。

7. 使用容器實(shí)現(xiàn)單例模式

public class 

SingletonManager { 
  private static Map<String, Object> objMap = new 

HashMap<String,Object>();
  private Singleton() { 
  }
  public static void 

registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
   

   objMap.put(key, instance) ;
    }
  }
  public static ObjectgetService(String 

key) {
    return objMap.get(key) ;
  }
}

用SingletonManager 將多種的單例類統(tǒng)一管理悦析,

在使用時(shí)根據(jù)key獲取對(duì)象對(duì)應(yīng)類型的對(duì)象。這種方式使得我們可以管理多種類型的單例,并且在使用時(shí)

可以通過統(tǒng)一的接口進(jìn)行獲取操作道媚,降低了用戶的使用成本,也對(duì)用戶隱藏了具體實(shí)現(xiàn)锈麸,降低了耦合度

掐隐。

總結(jié)

到這里七中寫法都介紹完了虑省,至于選擇用哪種形式的單例模式,取決于你的項(xiàng)目本身熟丸,是否

是有復(fù)雜的并發(fā)環(huán)境光羞,還是需要控制單例對(duì)象的資源消耗纱兑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末潜慎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子垒手,更是在濱河造成了極大的恐慌科贬,老刑警劉巖榜掌,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竞穷,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)看政,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門呆贿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來做入,“玉大人,你說我怎么就攤上這事竟块『耍” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵浪秘,是天一觀的道長蒋情。 經(jīng)常有香客問我埠况,道長,這世上最難降的妖魔是什么棵癣? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任辕翰,我火速辦了婚禮,結(jié)果婚禮上狈谊,老公的妹妹穿的比我還像新娘喜命。我一直安慰自己,他們只是感情好的畴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布渊抄。 她就那樣靜靜地躺著,像睡著了一般丧裁。 火紅的嫁衣襯著肌膚如雪护桦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天煎娇,我揣著相機(jī)與錄音二庵,去河邊找鬼。 笑死缓呛,一個(gè)胖子當(dāng)著我的面吹牛催享,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哟绊,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼因妙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了票髓?” 一聲冷哼從身側(cè)響起攀涵,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洽沟,沒想到半個(gè)月后以故,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裆操,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年怒详,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踪区。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昆烁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朽缴,到底是詐尸還是另有隱情善玫,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站茅郎,受9級(jí)特大地震影響蜗元,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜系冗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一奕扣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掌敬,春花似錦惯豆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至华临,卻和暖如春芯杀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雅潭。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工揭厚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扶供。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓筛圆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親椿浓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子太援,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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