設(shè)計(jì)模式之一:單例模式

摘要:設(shè)計(jì)模式之一:單例模式目錄介紹1.單例模式介紹2.單例模式定義3.單例模式使用場景4.單例模式的實(shí)現(xiàn)方式 4.1 懶漢式【線程不安全】 4.2 懶漢式【****synchronized 線程安全】 4.

設(shè)計(jì)模式之一:單例模式

目錄介紹

1.單例模式介紹

2.單例模式定義

3.單例模式使用場景

4.單例模式的實(shí)現(xiàn)方式

4.1 懶漢式【線程不安全】

4.2 懶漢式【****synchronized 線程安全】

4.3 餓漢式【線程安全】

4.4 DCL雙重校驗(yàn)?zāi)J健揪€程安全】

4.5 靜態(tài)內(nèi)部類單例模式【線程安全】

4.6 枚舉單例【線程安全】

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

5.Android源碼中單例

5.1 InputMethodManager中使用單例模式

5.2 LayoutInflater使用的單例模式

5.2 通過Context獲取系統(tǒng)級服務(wù)的單例模式

6.單例模式總結(jié)

7.其他

0.本人寫的綜合案例

案例

說明及截圖

模塊:新聞,音樂,視頻,圖片,唐詩宋詞,快遞,天氣,記事本,閱讀器等等

接口:七牛,阿里云,天行,干貨集中營,極速數(shù)據(jù),追書神器等等

1.單例模式介紹

單例模式是應(yīng)用最廣的模式,也是我最先知道的一種設(shè)計(jì)模式,在深入了解單例模式之前,每當(dāng)遇到如:getInstance()這樣的創(chuàng)建實(shí)例的代碼時(shí),我都會(huì)把它當(dāng)做一種單例模式的實(shí)現(xiàn)。

單例模式特點(diǎn)

構(gòu)造函數(shù)不對外開放,一般為private

通過一個(gè)靜態(tài)方法或者枚舉返回單例類對象

確保單例類的對象有且只有一個(gè),尤其是在多線程的環(huán)境下

確保單例類對象在反序列化時(shí)不會(huì)重新構(gòu)造對象

2.單例模式定義

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

3.單例模式使用場景

應(yīng)用中某個(gè)實(shí)例對象需要頻繁的被訪問。

應(yīng)用中每次啟動(dòng)只會(huì)存在一個(gè)實(shí)例。如賬號系統(tǒng),數(shù)據(jù)庫系統(tǒng)。

4.單例模式的實(shí)現(xiàn)方式

4.1 懶漢式【線程不安全】

懶漢式代碼//懶漢式單例類.在第一次調(diào)用的時(shí)候?qū)嵗约?public class Singleton { //私有的構(gòu)造函數(shù) private Singleton() {} //私有的靜態(tài)變量 private static Singleton single=null; //暴露的公有靜態(tài)方法 public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }

代碼分析懶漢式(線程不安全)的單例模式分為三個(gè)部分:私有的構(gòu)造方法,私有的全局靜態(tài)變量,公有的靜態(tài)方法。 起到重要作用的是靜態(tài)修飾符static關(guān)鍵字,我們知道在程序中,任何變量或者代碼都是在編譯時(shí)由系統(tǒng)自動(dòng)分配內(nèi)存來存儲(chǔ)的,而所謂靜態(tài)就是指在編譯后所分配的內(nèi)存會(huì)一直存在,直到程序退出內(nèi)存才會(huì)釋放這個(gè)空間,因此也就保證了單例類的實(shí)例一旦創(chuàng)建,便不會(huì)被系統(tǒng)回收,除非手動(dòng)設(shè)置為null。

優(yōu)缺點(diǎn)優(yōu)點(diǎn):延遲加載(需要的時(shí)候才去加載) 缺點(diǎn): 線程不安全,在多線程中很容易出現(xiàn)不同步的情況,如在數(shù)據(jù)庫對象進(jìn)行的頻繁讀寫操作時(shí)。

4.2 懶漢式【**synchronized 線程安全】**

懶漢式代碼public class Singleton { //私有的靜態(tài)變量 private static Singleton instance; //私有的構(gòu)造方法 private Singleton (){}; //公有的同步靜態(tài)方法 public static **synchronized** Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

代碼分析這種單例實(shí)現(xiàn)方式的getInstance()方法中添加了synchronized 關(guān)鍵字,也就是告訴Java(JVM)getInstance是一個(gè)同步方法。 同步的意思是當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)類中的這個(gè)synchronized同步方法時(shí), 一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行,另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完才能執(zhí)行,因此同步方法使得線程安全,保證了單例只有唯一個(gè)實(shí)例。

優(yōu)缺點(diǎn)優(yōu)點(diǎn):解決了線程不安全的問題。 缺點(diǎn):效率有點(diǎn)低,每次調(diào)用實(shí)例都要判斷同步鎖 它的缺點(diǎn)在于每次調(diào)用getInstance()都進(jìn)行同步,造成了不必要的同步開銷。這種模式一般不建議使用。

4.3 餓漢式【線程安全】

餓漢式代碼//餓漢式單例類.在類初始化時(shí),已經(jīng)自行實(shí)例化 public class Singleton { //static修飾的靜態(tài)變量在內(nèi)存中一旦創(chuàng)建,便永久存在 private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }

代碼分析餓漢式在類創(chuàng)建的同時(shí)就已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對象供系統(tǒng)使用,以后不再改變,所以天生是線程安全的。其中instance=new Singleton()可以寫成: static { instance = new Singleton(); }

4.4 DCL雙重校驗(yàn)?zāi)J?/b>

DCL雙重校驗(yàn)?zāi)J酱apublic class Singleton { private static Singleton singleton; //靜態(tài)變量 private Singleton (){} //私有構(gòu)造函數(shù) public static Singleton getInstance() { if (singleton == null) { //第一層校驗(yàn) synchronized (Singleton.class) { if (singleton == null) { //第二層校驗(yàn) singleton = new Singleton(); } } } return singleton; } }

代碼分析這種模式的亮點(diǎn)在于getInstance()方法上,其中對singleton 進(jìn)行了兩次判斷是否空,第一層判斷是為了避免不必要的同步,第二層的判斷是為了在null的情況下才創(chuàng)建實(shí)例。

優(yōu)缺點(diǎn)優(yōu)點(diǎn):在并發(fā)量不多,安全性不高的情況下或許能很完美運(yùn)行單例模式 缺點(diǎn):不同平臺(tái)編譯過程中可能會(huì)存在嚴(yán)重安全隱患。

模擬分析假設(shè)線程A執(zhí)行到了singleton = new Singleton(); 語句,這里看起來是一句代碼,但是它并不是一個(gè)原子操作,這句代碼最終會(huì)被編譯成多條匯編指令,它大致會(huì)做三件事情 (a)給Singleton的實(shí)例分配內(nèi)存 (b)調(diào)用Singleton()的構(gòu)造函數(shù),初始化成員字段 (c)將singleton對象指向分配的內(nèi)存空間(即singleton不為空了) 但是由于Java編譯器允許處理器亂序執(zhí)行,以及在jdk1.5之前,JMM(Java Memory Model:java內(nèi)存模型)中Cache、寄存器、到主內(nèi)存的回寫順序規(guī)定,上面的步驟b 步驟c的執(zhí)行順序是不保證了。也就是說執(zhí)行順序可能是a-b-c,也可能是a-c-b,如果是后者的指向順序,并且恰恰在c執(zhí)行完畢,b尚未執(zhí)行時(shí),被切換到線程B中,這時(shí)候因?yàn)閟ingleton在線程A中執(zhí)行了步驟c了,已經(jīng)非空了,所以,線程B直接就取走了singleton,再使用時(shí)就會(huì)出錯(cuò)。這就是DCL失效問題。 但是在JDK1.5之后,官方給出了volatile關(guān)鍵字,將singleton定義的代碼改成: private volatile static Singleton singleton; //使用volatile 關(guān)鍵字

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

靜態(tài)內(nèi)部類單例模式public class Singleton { private Singleton (){} ;//私有的構(gòu)造函數(shù) public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } //定義的靜態(tài)內(nèi)部類 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); //創(chuàng)建實(shí)例的地方 } }

優(yōu)缺點(diǎn)優(yōu)點(diǎn):延遲加載,線程安全(java中class加載時(shí)互斥的),也減少了內(nèi)存消耗

代碼分析當(dāng)?shù)谝淮渭虞dSingleton 類的時(shí)候并不會(huì)初始化INSTANCE ,只有第一次調(diào)用Singleton 的getInstance()方法時(shí)才會(huì)導(dǎo)致INSTANCE 被初始化。因此,第一次調(diào)用getInstance()方法會(huì)導(dǎo)致虛擬機(jī)加載SingletonHolder 類,這種方式不僅能夠確保單例對象的唯一性,同時(shí)也延遲了單例的實(shí)例化。

4.6 枚舉單例

枚舉單例代碼

publicenumSingleton{? //enum枚舉類INSTANCE; public void whateverMethod() { } }

代碼分析

枚舉單例模式最大的優(yōu)點(diǎn)就是寫法簡單,枚舉在java中與普通的類是一樣的,不僅能夠有字段,還能夠有自己的方法,最重要的是默認(rèn)枚舉實(shí)例是線程安全的,并且在任何情況下,它都是一個(gè)單例。即使是在反序列化的過程,枚舉單例也不會(huì)重新生成新的實(shí)例。而其他幾種方式,必須加入如下方法:才能保證反序列化時(shí)不會(huì)生成新的對象。privateObjectreadResolve()throwsObjectStreamException{returnINSTANCE;}

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

代碼

publicclass SingletonManager {privatestaticMap objMap =newHashMap();//使用HashMap作為緩存容器privateSingleton() {  }publicstaticvoidregisterService(Stringkey,Objectinstance) {if(!objMap.containsKey(key) ) {      objMap.put(key, instance) ;//第一次是存入Map}  }publicstaticObjectgetService(Stringkey) {returnobjMap.get(key) ;//返回與key相對應(yīng)的對象}}

代碼分析

在程序的初始,將多種單例模式注入到一個(gè)統(tǒng)一的管理類中,在使用時(shí)根據(jù)key獲取對應(yīng)類型的對象。

5.Android源碼中單例

5.1 InputMethodManager中使用單例模式

5.2 LayoutInflater使用的單例模式

5.2 通過Context獲取系統(tǒng)級服務(wù)的單例模式

6.單例模式總結(jié)

總結(jié):不管以哪種形式實(shí)現(xiàn)單例模式,它們的核心原理是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)公有方法獲取一個(gè)唯一的實(shí)例,在這個(gè)獲取的過程中必須保證線程的安全,同時(shí)也要防止反序列化導(dǎo)致重新生成實(shí)例對象。

綜合考慮:推薦使用**4.4 DCL雙重校驗(yàn)?zāi)J剑?***4.5 靜態(tài)內(nèi)部類單例模式等等**

單例對象如果持有Context,那么很容易引發(fā)內(nèi)存泄漏,此時(shí)要注意傳遞給單例對象的Context最好是Application Context

原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,996評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評論 2 374

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