Android 設(shè)計模式:(二)單例模式

前言
本文是對《Adroid 源碼設(shè)計模式解析與實戰(zhàn)》 何紅輝缕陕、關(guān)愛民 著 人民郵電出版社所做的讀書筆記。文章是對本書的一些列學(xué)習(xí)筆記疙挺,如若有侵犯到作者權(quán)益扛邑,還望作者能聯(lián)系我,我會及時下架铐然。
這本書不錯蔬崩,有興趣的同學(xué)可以買原書看看。
感興趣的朋友歡迎加入學(xué)習(xí)小組QQ群: 193765960搀暑。

版權(quán)歸作者所有沥阳,如有轉(zhuǎn)發(fā),請注明文章出處:https://xiaodanchen.github.io/archives/
相關(guān)文章:

Android 設(shè)計模式:(一)面向?qū)ο蟮牧笤瓌t
Android 設(shè)計模式:(二)單例模式
Android 設(shè)計模式:(三)Builder模式
Android 設(shè)計模式:(四)原型模式
Android 設(shè)計模式:(五)工廠方法模式
Android 設(shè)計模式:(六)抽象工廠模式
Android 設(shè)計模式:(七)策略模式

1. 單例模式的定義

單例模式:確保某一個類只有一個實例险掀,而且自行實例化并向整個系統(tǒng)提供這個實例沪袭。

2. 單例模式的實現(xiàn)

在正式介紹單例模式之前,我們有必要了解一下 instance = new Singleton()這樣一條語句樟氢。乍一看這是一天簡單的語句冈绊,用來生成一個Singleton類的實例,但實際上他不是一條原子操作埠啃。這條代碼最終會被編譯成多條匯編指令死宣,他大致做了3件事情:
(1)給Singleton實例分配內(nèi)存。
(2)調(diào)用Singleton()構(gòu)造方法碴开,初始化成員字段毅该。
(3)將instance對象指向分配的內(nèi)存空間(此時instance就不是null了)博秫。
另外,JVM執(zhí)行上面三條匯編指令的順序是不定的眶掌,有可能是1-2-3挡育,也有可能是1-3-2。

2.1餓漢模式

代碼示例

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

優(yōu)缺點

優(yōu)點:

  • 線程安全朴爬,無需關(guān)注多線程的問題即寒。
  • 加載沒有延時:在類創(chuàng)建的同時,就已經(jīng)創(chuàng)建好類的實例
  • 寫法簡單

缺點:

  • 由于在類創(chuàng)建的時候召噩,就創(chuàng)建了實例(不管你會不會用到)母赵,那么就有可能會緩存很多用戶根本用不到的實例。
  • 如果類中的實例會消耗較大量的內(nèi)存具滴,則要慎用餓漢模式創(chuàng)建單例凹嘲。

2.2 懶漢模式

代碼示例

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

優(yōu)缺點

優(yōu)點:

  • 在使用時才會創(chuàng)建實例,在一定程度上節(jié)省了資源构韵。
    缺點:
  • 第一次加載時需要實例化周蹭,反應(yīng)稍慢。
  • 加了同步鎖贞绳,造成不必要的同步開銷谷醉。
  • 如果忘記加同步鎖,則是線程不安全的冈闭。

2.3 Double Check Lock

代碼示例

public class Singleton{
  /**
  * volatile: 
  * 告訴JVM不要對volitile所修飾的變量進行拷貝。
  * 這樣就保證了instance不會在線程內(nèi)存中保存拷貝抖单,instance每次都從主內(nèi)存中讀取萎攒。
  *
  */
  private volatile static Singleton instance;
  private Singleton(){}
  
  public static Singleton getInstance(){
    if(null == instance){
      synchornized(Singleton.class){
         if(null == instance){
           intance = new Singleton();
         }
      }
    }
    return instance;
  }
}

優(yōu)缺點

優(yōu)點:

  • 資源利用率高,只有在第一次調(diào)用時才會分配資源矛绘。
  • 相較于懶漢模式耍休,加載速度更快。
  • 在一定程度上避免了多余的同步货矮,減輕了線程安全的問題羊精。

缺點:

  • 第一次加載時存在延時,反應(yīng)較慢囚玫。
  • 存在失效的情況(雖然概率較行酢):正如上文所說,如果當(dāng)前線程調(diào)用new Singleton()對應(yīng)的匯編的執(zhí)行順序是1-3-2抓督,當(dāng)有新的線程調(diào)用getinstance()時燃少,instance沒有初始化卻非空,就造成了instance失效铃在。

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

代碼示例

public class Singleton{
  private Singleton(){}
  
  public static Singleton getInstance(){
    return SingletonHolder.instance;
  }
  
  /**
  * 靜態(tài)內(nèi)部類
  */
  private static class SinletonHolder{
    private static final Singleton instace = new Singleton();
  }
}

優(yōu)缺點

第一次加載Singleton類時并不會初始化instance阵具,只有在第一次調(diào)用Singleton的getInstace()方法時才會導(dǎo)致instance初始化碍遍。因為,第一次調(diào)用getInstace()時阳液,JVM才會加載SingletonHolder類怕敬。
這種方式不僅能夠確保線程的安全,而且延遲了實例化帘皿,避免了餓漢模式的資源浪費东跪,同時也能夠保證單例對象的唯一性。

2.5 枚舉單例

代碼示例

public enum SingletonEnum{
  INSTANCE;
  public void doSomething(){
    ...
  }
}

優(yōu)缺點

  • 寫法簡單
  • 線程安全
  • 在任何情況下(即使反序列化)矮烹,他都是一個實例越庇。2.1到2.4介紹的幾種方法,在反序列化(將實例對象寫入磁盤再讀取出來)時無法保證實例的唯一性奉狈。因為反序列化時系統(tǒng)會通過特殊的途徑創(chuàng)建一個類的新實例卤唉,相當(dāng)于調(diào)用了該類的構(gòu)造函數(shù),哪怕構(gòu)造函數(shù)是私有的仁期。反序列化操作提供了一個特別的鉤子函數(shù)readResolve()桑驱,這個方法可以讓開發(fā)人員控制對象的發(fā)序列化。例如跛蛋,上述幾個實現(xiàn)單例模式的方法要想杜絕反序列化時重新生成對象熬的,那么必須加入如下方法:
private Object readResolve() throw ObjectStreamException{
  return instance;
}

2.6 使用容器實現(xiàn)單例

代碼示例

public class SingletonManager{
  private static Map<String,Object> objMap =  new HashMap<String,Object>();
  private SingletonManager(){}
  
  public static void registerService(String key, Object instance){
    if(!objMap.containsKey(key)){
      objMap.put(key,instance);
    }
  }
  
  public static Object getService(String key){
    return objMap.get(key);
  }
}

優(yōu)缺點

在程序的初始,將多中單例類型注入到一個統(tǒng)一的管理類中赊级,在使用時根據(jù)key獲取對應(yīng)類型的對象押框。這種方式使得我們可以管理多種類型的單例,并且在使用時可以通過統(tǒng)一的接口進行獲取操作理逊,降低了用戶的使用成本橡伞,也對用戶隱藏了具體實現(xiàn),降低了耦合度晋被。
例如系統(tǒng)服務(wù)兑徘,就是這種模式:getSystemService(System.xx_SERVICE)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市羡洛,隨后出現(xiàn)的幾起案子挂脑,更是在濱河造成了極大的恐慌,老刑警劉巖欲侮,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崭闲,死亡現(xiàn)場離奇詭異,居然都是意外死亡锈麸,警方通過查閱死者的電腦和手機镀脂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忘伞,“玉大人薄翅,你說我怎么就攤上這事沙兰。” “怎么了翘魄?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵鼎天,是天一觀的道長。 經(jīng)常有香客問我暑竟,道長斋射,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任但荤,我火速辦了婚禮罗岖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腹躁。我一直安慰自己桑包,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布纺非。 她就那樣靜靜地躺著哑了,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烧颖。 梳的紋絲不亂的頭發(fā)上弱左,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音炕淮,去河邊找鬼拆火。 笑死,一個胖子當(dāng)著我的面吹牛涂圆,可吹牛的內(nèi)容都是我干的榜掌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼乘综,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了套硼?” 一聲冷哼從身側(cè)響起卡辰,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎邪意,沒想到半個月后九妈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡雾鬼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年萌朱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片策菜。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡晶疼,死狀恐怖酒贬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翠霍,我是刑警寧澤锭吨,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站寒匙,受9級特大地震影響零如,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锄弱,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一考蕾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧会宪,春花似錦肖卧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至河劝,卻和暖如春壁榕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赎瞎。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工牌里, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人务甥。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓牡辽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敞临。 傳聞我的和親對象是個殘疾皇子态辛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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