溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

設(shè)計(jì)模式-由淺到深的單例模式

發(fā)布時(shí)間:2020-06-15 11:40:44 來(lái)源:網(wǎng)絡(luò) 閱讀:264 作者:張立達(dá) 欄目:網(wǎng)絡(luò)安全

前言:說(shuō)起單例模式,可能大家都熟悉,可以說(shuō)是設(shè)計(jì)模式中出現(xiàn)頻率最高的一個(gè),為了徹底弄清單例,在這里我將說(shuō)明何為單例,單例模式的演變,已經(jīng)和靜態(tài)類之間的區(qū)別等。

1:概念

何為單例,就是在一個(gè)應(yīng)用程序中只能有一個(gè)實(shí)例,就是保證對(duì)象只能被new一次。

2:懶漢模式

懶漢我覺(jué)得這個(gè)名字很形象,就是很懶,所以別的對(duì)象加載,它就不加載,你調(diào)用我的時(shí)候我在加載。比喻hibernate中也有懶模式。ok我們開(kāi)始吧

2.1:非線程安全

一天小明去面試,面試官說(shuō),你給我寫個(gè)單例模式,小明一想這實(shí)在太簡(jiǎn)單了不暇思索很快寫出來(lái)了如下的單例模式

設(shè)計(jì)模式-由淺到深的單例模式

 1 public class Singleton { 2     private static Singleton singleton; 3     public static Singleton getSingleton() 4     { 5         if(singleton==null) 6         { 7             singleton=new Singleton(); 8         } 9         return singleton;10     }11 }

設(shè)計(jì)模式-由淺到深的單例模式

然后面試官一看說(shuō):你這在高并發(fā)的時(shí)候有可能會(huì)產(chǎn)生多個(gè)singleton實(shí)例,小明一想怎么會(huì)呢,面試官解釋說(shuō),如果有2個(gè)線程T1,T2同時(shí)執(zhí)行,當(dāng)T1執(zhí)行到第6行的時(shí)候,時(shí)間片段到,系統(tǒng)開(kāi)始讓T2執(zhí)行,執(zhí)行到第9行,然后T1又開(kāi)始執(zhí)行,因?yàn)門1已經(jīng)做過(guò)判斷此時(shí)并不知道singleton已經(jīng)被實(shí)例化,所以singleton此時(shí)再次被實(shí)例化,這樣你系統(tǒng)就有2個(gè)singleton對(duì)象,那還是單例嗎,小明恍然大悟,這個(gè)我能解決,馬上又寫出下面這個(gè)

2.2:線程安全

設(shè)計(jì)模式-由淺到深的單例模式

 1 public class Singleton { 2     private static Singleton singleton; 3      4     public synchronized static Singleton getSingleton() 5     { 6         if(singleton==null) 7             { 8                 singleton=new Singleton(); 9             }10             return singleton;11     }

設(shè)計(jì)模式-由淺到深的單例模式

面試官一看,加上了線程同步,這個(gè)時(shí)候確實(shí)能保證線程安全問(wèn)題,但是又提出了疑問(wèn),如果現(xiàn)在singleton已經(jīng)被實(shí)例化了,如果10個(gè)線程同時(shí)訪問(wèn),每次都要等待那么勢(shì)必造成性能極大的消耗,你有沒(méi)有別的方案解決問(wèn)題,小明思考一分鐘又寫下了下面一段代碼

2.3:雙重校驗(yàn)

設(shè)計(jì)模式-由淺到深的單例模式

 1 public class Singleton { 2     private static Singleton singleton; 3      4     public  static Singleton getSingleton() 5     { 6         if(singleton==null) 7         { 8             synchronized (Singleton.class) { 9                 if(singleton==null)10                 {11                     singleton=new Singleton();12                 }13             }14         }15         return singleton;16     }

設(shè)計(jì)模式-由淺到深的單例模式

面試官一看,果真在上面一段代碼的基礎(chǔ)上提升了不少性能,減少了不必要的等待,但是仔細(xì)一看說(shuō)你這代碼有點(diǎn)問(wèn)題,并不能保證線程的安全,小明說(shuō)怎么說(shuō)呢,然后面試官解釋說(shuō):如果有T1,T2兩個(gè)線程,T1線程運(yùn)行第六行發(fā)現(xiàn)singleton==null,就進(jìn)入第8行,開(kāi)始對(duì)singleton進(jìn)行實(shí)例化,因?yàn)閷?shí)例化中分為三步,第一步為對(duì)象開(kāi)辟內(nèi)存空間,第二步為對(duì)象初始化,第三步是把這個(gè)內(nèi)存地址賦給singleton,但是因?yàn)閖ava的內(nèi)存模式允許無(wú)序?qū)懭耄@樣一來(lái)會(huì)導(dǎo)致第二步和第三步位置調(diào)換,那么這樣一來(lái)就壞了,如果先允許第一步和第三步了,但是此時(shí)并沒(méi)有對(duì)對(duì)象進(jìn)行初始化,恰恰在此時(shí)T2進(jìn)入了第6行,經(jīng)過(guò)判斷singleton不為null,那么就會(huì)返回一個(gè)沒(méi)有被初始化的對(duì)象。小明聽(tīng)了覺(jué)得對(duì)啊,他說(shuō)我把內(nèi)存模式改為不允許無(wú)序?qū)懭氩痪托辛藛?,于是就把代碼修改為

設(shè)計(jì)模式-由淺到深的單例模式

 1 public class Singleton { 2     private volatile static Singleton singleton;//表示有序?qū)懭?nbsp;3      4     public  static Singleton getSingleton() 5     { 6         if(singleton==null) 7         { 8             synchronized (Singleton.class) { 9                 if(singleton==null)10                 {11                     singleton=new Singleton();12                 }13             }14         }15         return singleton;16     }

設(shè)計(jì)模式-由淺到深的單例模式

注釋1:對(duì)象實(shí)例化三步我這里做一個(gè)比喻,某個(gè)公司給員工分配一間寢室(指的就是在堆中開(kāi)辟了空間)然后呢給房子進(jìn)行一些標(biāo)配比喻分個(gè)空調(diào)、洗衣機(jī)什么的(對(duì)象初始化),在然后呢把鑰匙給到員工手里(對(duì)象進(jìn)行賦值)。

3:餓漢模式

面試官又問(wèn)你知道餓漢模式怎么寫的嗎,小明一聽(tīng):哦餓漢,不就是很著急自己馬上進(jìn)行實(shí)例化,生怕自己無(wú)法實(shí)例化嗎,這個(gè)簡(jiǎn)單馬上寫了一個(gè)餓漢

設(shè)計(jì)模式-由淺到深的單例模式

public class Singleton {    
    private static Singleton singleton=new Singleton();    public  static Singleton getSingleton()
    {        return singleton;
    }
}

設(shè)計(jì)模式-由淺到深的單例模式

面試官一看確實(shí)不錯(cuò)。

4:內(nèi)部類模式

小明一看上面的模式,自己突發(fā)奇想,餓漢模式著急創(chuàng)建對(duì)象,在加載時(shí)候消耗性能,而懶漢模式又存在線程安全問(wèn)題(優(yōu)化后沒(méi)有了)能不能結(jié)合一下呢,突然告訴面試官我還有一個(gè)比較好的方式來(lái)實(shí)現(xiàn),然后他寫了下面代碼

設(shè)計(jì)模式-由淺到深的單例模式

1 public class Singleton {    
2     private static class SingletonManager{3         private final static  Singleton SINGLETON=new Singleton();4     }5     public final static Singleton getSingleton()6     {7         return SingletonManager.SINGLETON;8     }

設(shè)計(jì)模式-由淺到深的單例模式

面試官一看,不錯(cuò)不錯(cuò),既保證了懶加載,同時(shí)也保證了線程安全問(wèn)題。

5:使用場(chǎng)景

面試官又問(wèn)小明,那么你知道使用場(chǎng)景嗎,小明想了想說(shuō),既然在應(yīng)用程序中只有一個(gè)單例,那么勢(shì)必是用于共享資源,比喻數(shù)據(jù)庫(kù)連接池,線程池等都可以用單例模式。

6:?jiǎn)卫J胶挽o態(tài)類區(qū)別

面試官繼續(xù)問(wèn):靜態(tài)類同樣也是產(chǎn)生一個(gè)對(duì)象,和單例具有高度相似你知道他們區(qū)別嗎,小明回答說(shuō)

1:面向?qū)ο笾杏腥筇匦岳^承,封裝和多態(tài),但是靜態(tài)類是不可以繼承的,所以從oo角度來(lái)說(shuō)靜態(tài)類并不符合面向?qū)ο?,他們的類是不可以被覆蓋,所以靈活性要比單例差的多

2:由于靜態(tài)類的特殊他在編譯器已經(jīng)進(jìn)行實(shí)例化了并不能提供懶加載模式

3:對(duì)于項(xiàng)目中如果進(jìn)行單元測(cè)試,由于方法不能覆蓋同樣為測(cè)試帶來(lái)了困難

4:由于靜態(tài)類在編譯器已經(jīng)都被實(shí)例化,所以要比單例性能要快,如果只需要執(zhí)行一些靜態(tài)方法這個(gè)時(shí)候可以采用靜態(tài)類

7:總結(jié)

單例模式看似簡(jiǎn)單,其實(shí)用起來(lái)還要考慮到很多問(wèn)題,現(xiàn)在我把這個(gè)過(guò)程基本總結(jié)了,當(dāng)然可能還有不足之處,歡迎指正。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI