Android設(shè)計(jì)模式探討--單例模式

核心原則:將構(gòu)造函數(shù)私有化衣撬,通過一個(gè)靜態(tài)內(nèi)部方法來(lái)獲取唯一實(shí)例.

單例模式的定義:確保某個(gè)類只有一個(gè)實(shí)例,避免產(chǎn)生多個(gè)對(duì)象來(lái)消耗過度資源。
下面介紹幾種常見實(shí)現(xiàn)單例模式的方法摔认。

餓漢模式
它是在聲明該靜態(tài)類時(shí)該對(duì)象已經(jīng)存在喧兄,并且初始化了.

public class Singleton{
  private  static Singleton mInstance = new Singleton();//注意這里的static无畔,因?yàn)橄旅嬲{(diào)用獲取到該實(shí)例的是靜態(tài)方法.
  public static Singleton getInstance() {//靜態(tài)方法
    return mInstance;
  }
  private Singleton() {//注意此處的構(gòu)造函數(shù)必須要用private來(lái)修飾
  }
}

優(yōu)點(diǎn):寫的比較簡(jiǎn)單,線程安全.
缺點(diǎn):消耗點(diǎn)資源,因?yàn)榧词鼓悴挥迷搯卫庇ǎo態(tài)存儲(chǔ)空間中仍然會(huì)分配空間給該實(shí)例.

懶漢模式
它是懶加載的模式.用的時(shí)候加載檩互,不用的時(shí)候不占用空間

public class Singleton{
private static Singleton mInstance;
public static synchronized Singleton getInstance() {//注意這里必須要加synchronized,否則多線程調(diào)用就會(huì)有問題咨演,獲取到不唯一的實(shí)例.
  if(mInstance == null) {
     mInstance =new Singleton();
  }
  return mInstance;
}
}

優(yōu)點(diǎn):多線程安全闸昨,比餓漢模式好點(diǎn),它是需要的時(shí)候才實(shí)例化Singleton對(duì)象。
缺點(diǎn):調(diào)用getInstance的時(shí)候因?yàn)榧恿藄ynchronized鎖饵较,所以其他的線程調(diào)用的時(shí)候必須等待拍嵌,這樣造成了不必要的資源開銷。

DCL模式
Double Check Lock 模式循诉,用的時(shí)候初始化横辆,而且不需要getInstance方法進(jìn)行同步

public class Singleton{
    private static volatile Singleton mInstance;//注意volatile這個(gè)關(guān)鍵字
    public static Singleton getInstance() {
       if(mInstance == null) {//第一次檢查
          synchronized(Singleton.class){//鎖的是Singleton.class文件確保多線程安全
          if(mInstance == null) {//第二次檢查
                mInstance =new Singleton();
           }
      }
   }
    return mInstance;
  }

}

volatile 這個(gè)關(guān)鍵字必須要用的原因
上面代碼中mInstance =new Singleton(); 其實(shí)并不是一個(gè)原子操作茄猫,編譯后大致做了下面3件事情
1)給Singleton分配內(nèi)存空間
2)構(gòu)造函數(shù)狈蚤,初始化成員變量
3)mInstance對(duì)象指向Singleton分配出來(lái)的存儲(chǔ)空間中

問題在于 Java編譯器允許處理器亂序執(zhí)行,所以上面的可能是1->3->2 比如兩個(gè)線程A,B分別調(diào)用了getInstance 靜態(tài)函數(shù)划纽,A執(zhí)行了 1->3->2的順序脆侮,當(dāng)執(zhí)行3的時(shí)候,B線程call getInstance 靜態(tài)函數(shù)獲取到的mInstance是非空的勇劣,直接返回靖避,這個(gè)時(shí)候B線程直接用這個(gè)實(shí)例就會(huì)有問題,因?yàn)榇藭r(shí)該實(shí)例還沒有初始化.這樣調(diào)用的話就會(huì)報(bào)錯(cuò).
基于上面的原因 JDK1.5之后引入了volatile這個(gè)關(guān)鍵字比默,使編譯器每次都是按1->2->3順序執(zhí)行幻捏,這樣就不會(huì)有多線程的問題,線程也安全命咐。

DCL的優(yōu)點(diǎn):資源的利用率高篡九,只有在使用的時(shí)候才初始化對(duì)應(yīng)的空間.而且高效的實(shí)現(xiàn)線程同步.
DCL的缺點(diǎn):使用了volatile關(guān)鍵字,第一次加載的速度上稍微慢了點(diǎn).

靜態(tài)內(nèi)部類
它是利用了Java虛擬機(jī)加載類的特性來(lái)解決了線程安全侈百,資源消耗等問題.

  public  class Singleton {

       private Singleton() {
        }

        public static Singleton getInstance() {
            return SingletonHolder.mInstance;
        }

        public static class SingletonHolder {
            private static final Singleton mInstance = new Singleton()
        }

 }

這種方式, 通過JVM的類加載方式(虛擬機(jī)會(huì)保證一個(gè)類的初始化在多線程環(huán)境中被正確的加鎖瓮下、同步), 來(lái)保證了多線程并發(fā)訪問的正確性,由于靜態(tài)內(nèi)部類的加載特性--在使用時(shí)候才加載钝域,所以實(shí)現(xiàn)了懶加載的模式讽坏。

優(yōu)點(diǎn):
實(shí)現(xiàn)線程安全,實(shí)現(xiàn)懶加載
缺點(diǎn):
必須依賴Java虛擬機(jī)

枚舉單例

public enum Singleton{
INSTANCE;
}

優(yōu)點(diǎn):?jiǎn)卧孛杜e不僅能避免多線程同步問題例证,防止反序列化時(shí)重新創(chuàng)建新的對(duì)象

Android 用單例的例子

 
public final class InputMethodManager {
static InputMethodManager sInstance;
...
   public static InputMethodManager getInstance() {
        synchronized (InputMethodManager.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
                IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
                sInstance = new InputMethodManager(service, Looper.getMainLooper());
            }
            return sInstance;
        }
    }
....

如InputMethodManager利用了懶加載的模式路呜,但是線程不安全.沒有加volatile關(guān)鍵字

public static synchronized CalendarDatabaseHelper getInstance(Contextcontext)  
{  
    if (sSingleton == null)  
    {  
       sSingleton = newCalendarDatabaseHelper(context);  
    }  
        return sSingleton;  
}  

采用懶漢模式的CalendarDatabaseHelper類,對(duì)Calendar數(shù)據(jù)庫(kù)操作

結(jié)論:
1)實(shí)現(xiàn)單例模式分3步:構(gòu)造器私有化织咧,聲明私有靜態(tài)變量胀葱,提供靜態(tài)獲取實(shí)例的方法.
2)如果是單線程推薦懶加載模式,如果是多線程推薦靜態(tài)內(nèi)部類的方式實(shí)現(xiàn)單例
3)對(duì)數(shù)據(jù)庫(kù)操作笙蒙,對(duì)資源訪問抵屿,對(duì)IO操作等最好提供單例模式來(lái)處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捅位,隨后出現(xiàn)的幾起案子轧葛,更是在濱河造成了極大的恐慌搂抒,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尿扯,死亡現(xiàn)場(chǎng)離奇詭異求晶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)衷笋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門芳杏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人辟宗,你說(shuō)我怎么就攤上這事爵赵。” “怎么了泊脐?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵亚再,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我晨抡,道長(zhǎng),這世上最難降的妖魔是什么则剃? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任耘柱,我火速辦了婚禮,結(jié)果婚禮上棍现,老公的妹妹穿的比我還像新娘调煎。我一直安慰自己,他們只是感情好己肮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布士袄。 她就那樣靜靜地躺著,像睡著了一般谎僻。 火紅的嫁衣襯著肌膚如雪娄柳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天艘绍,我揣著相機(jī)與錄音赤拒,去河邊找鬼。 笑死诱鞠,一個(gè)胖子當(dāng)著我的面吹牛挎挖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播航夺,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蕉朵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了阳掐?” 一聲冷哼從身側(cè)響起始衅,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤冷蚂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后觅闽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帝雇,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年蛉拙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尸闸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孕锄,死狀恐怖吮廉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畸肆,我是刑警寧澤宦芦,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站轴脐,受9級(jí)特大地震影響调卑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜大咱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一恬涧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碴巾,春花似錦溯捆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至煮仇,卻和暖如春劳跃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欺抗。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工售碳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绞呈。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓贸人,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親佃声。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艺智,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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