關(guān)于設(shè)計(jì)模式活合,我覺得是個(gè)程序員就應(yīng)該聽過白指,但是很多人用的時(shí)候還是一臉懵逼告嘲,今天26歲老司機(jī)總結(jié)一下我們常用的設(shè)計(jì)模式
設(shè)計(jì)模式一共有23種:
- 創(chuàng)建型(5種):主要用于處理對(duì)象的創(chuàng)建,實(shí)例化對(duì)象:
單例赋焕,建造者仰楚,原型,工廠方法蜜氨,抽象工廠
結(jié)構(gòu)型(7種):處理類或?qū)ο箝g的組合
適配器飒炎,裝飾者笆豁,結(jié)合,橋接煞赢,外觀照筑,享元凝危,代理
行為型(11種):描述類或?qū)ο笤鯓舆M(jìn)行交互和職責(zé)分配
策略,觀察者蛾默,迭代器支鸡,命令趁窃,備忘錄,中介者瀑构,解釋器检碗,訪問者,責(zé)任鏈折剃,狀態(tài),模板方法
今天我們主要研究一下單例模式:
單例模式(Singleton Pattern)
作用:保證 類在內(nèi)存中 的 對(duì)象唯一性边篮。
適用場(chǎng)景:
1.避免創(chuàng)建多個(gè)實(shí)例浪費(fèi)資源
2.避免多個(gè)實(shí)例因多次調(diào)用而出現(xiàn)錯(cuò)誤
3.一般寫工具類奏甫,線程池阵子,緩存,數(shù)據(jù)庫會(huì)用到色乾。
套路(三個(gè)要點(diǎn)):1.不允許在類外new對(duì)象 —— 構(gòu)造方法私有化
2.在類中創(chuàng)建對(duì)象 —— 通過new在本類中創(chuàng)建一個(gè)實(shí)例
3.對(duì)外提供獲取該實(shí)例的方法 —— 定義公有方法返回創(chuàng)建的實(shí)例
餓漢與懶漢的區(qū)別
前者在類裝載時(shí)就實(shí)例化暖璧,后者只有在第一次被使用時(shí)才實(shí)例化澎办。
(餓漢的優(yōu)點(diǎn)是避免線程同步問題金砍,缺點(diǎn)是即使沒用到這個(gè)實(shí)例還是會(huì)加載)
(懶漢的優(yōu)點(diǎn)是實(shí)現(xiàn)了懶加載,但需要解決線程安全問題至会!)
5種常用單例套路:
1)餓漢式,沒有實(shí)現(xiàn)懶加載~
public class Singleton() {
private static Singleton instance = new Singleton();
private Singleton(){ }
public static Singleton getInstance() {
return instance;
}
}
//獲取單例對(duì)象
Singleton mSingleton = Singleton.getInstance();
2)懶漢式
雖然達(dá)到了懶加載昆著,但是卻存在線程安全問題术陶,比如有兩個(gè)線程都
剛好執(zhí)行完if(instance == null)梧宫,接著準(zhǔn)備執(zhí)行instance = new Singleton()
語句,這樣的結(jié)果會(huì)導(dǎo)致我們實(shí)例化了兩個(gè)Singleton對(duì)象脓豪,
為了解決線程不安全問題扫夜,可以對(duì)getInstance()方法加鎖。
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
3)懶漢式加鎖版
首先普及synchronized當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí)堕阔,一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行超陆。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊时呀。
為getInstance方法加鎖雖然保證了線程安全捐韩,但是每次執(zhí)行g(shù)etInstance()
都需要同步,而實(shí)例化對(duì)象只需要執(zhí)行一次就夠了瞧预,后面獲取該示例垢油,
應(yīng)該直接return就好了,方法同步效率太低滩愁,一種改進(jìn)后的寫法是:
synchronized (Singleton.class) { instance = new Singleton(); }
但是硝枉,這樣寫依然是線程不安全的妻味,如果你還是想用懶漢式的話责球,推薦
雙重檢查鎖定(DCL雏逾,Double Check Lock)。
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4)懶漢式雙重校驗(yàn)鎖(DCL)
首先普及Volatile:Volatile修飾的成員變量在每次被線程訪問時(shí)屑宠,都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值侨把。而且秋柄,當(dāng)成員變量發(fā)生變化時(shí)骇笔,強(qiáng)迫線程將變化值回寫到共享內(nèi)存笨触。這樣在任何時(shí)刻芦劣,兩個(gè)不同的線程總是看到某個(gè)成員變量的同一個(gè)值。
代碼中進(jìn)行了兩次if檢查说榆,這樣就可以保證線程安全虚吟,初始化一次后,
后面再次訪問時(shí)签财,if檢查串慰,直接return 實(shí)例化對(duì)象。volatile是1.5后
引入的唱蒸,volatile關(guān)鍵字會(huì)屏蔽Java虛擬機(jī)所做的一些代碼優(yōu)化邦鲫,會(huì)導(dǎo)
致系統(tǒng)運(yùn)行效率降低,而更好的寫法是使用靜態(tài)內(nèi)部類來實(shí)現(xiàn)單例神汹!
public class Singleton{
private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
5)靜態(tài)內(nèi)部類實(shí)現(xiàn)單例(推薦)
和餓漢式類似庆捺,都是通過類加載機(jī)制來保證初始化實(shí)例的
時(shí)候只有一個(gè)線程,從而避免線程安全問題屁魏,餓漢式的
Singleton類被加載時(shí)疼燥,就會(huì)實(shí)例化披诗,而靜態(tài)內(nèi)部類這種剥槐,
當(dāng)Singleton類被加載時(shí),不會(huì)立即實(shí)例化蕊苗,調(diào)用getInstance()
方法才會(huì)裝載SingletonHolder類喉刘,從而完成Singleton的實(shí)例化造锅。
public class Singleton {
private Singleton() { }
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton()
}
}
結(jié)論:由以上結(jié)果可以得知單例模式為一個(gè)面向?qū)ο蟮膽?yīng)用程序提供了對(duì)象惟一的訪問點(diǎn)肺素,不管它實(shí)現(xiàn)何種功能,整個(gè)應(yīng)用程序都會(huì)同享一個(gè)實(shí)例對(duì)象塌西。
對(duì)于單例模式的幾種實(shí)現(xiàn)方式筹淫,知道餓漢式和懶漢式的區(qū)別殊霞,線程安全,資源加載的時(shí)機(jī),還有懶漢式為了實(shí)現(xiàn)線程安全的3種方式的細(xì)微差別。
參考:http://www.reibang.com/p/b84a251a8838
Our youth never dies,just fades away.
嗨~我是夏尼采龄章,一個(gè)有夢(mèng)想的IT男
每周輸出3篇有用的文章,目標(biāo)是簽約簡書锚贱。
如果文章對(duì)您有幫助晋修,希望能點(diǎn)個(gè)贊或者關(guān)注我。
您的關(guān)注和點(diǎn)贊是對(duì)我最大的鼓勵(lì)睁本,感謝您的閱讀