網(wǎng)站建設(shè)優(yōu)化托管優(yōu)秀的軟文
單例模式,是設(shè)計(jì)模式的一種。
在計(jì)算機(jī)這個(gè)圈子中,大佬們針對(duì)一些典型的場(chǎng)景,給出了一些典型的解決方案。
目錄
單例模式
餓漢模式
懶漢模式
線程安全
單例模式
單例模式又可以理解為是單個(gè)實(shí)例(對(duì)象)
在有些場(chǎng)景中,有特定的類,只能創(chuàng)建出一個(gè)實(shí)例,不應(yīng)該創(chuàng)建多個(gè)實(shí)例。使用了單例模式以后,此時(shí)想要?jiǎng)?chuàng)建多個(gè)實(shí)例就變得很困難~
Java中的單例模式就是針對(duì)上述的需求場(chǎng)景進(jìn)行了更強(qiáng)制的保證。通過(guò)巧用Java的現(xiàn)有語(yǔ)法,達(dá)成了某個(gè)類只能被創(chuàng)建出一個(gè)實(shí)例這樣的效果。
餓漢模式
Java代碼中的每個(gè)類,都會(huì)在編譯完成后得到.class文件,JVM運(yùn)行時(shí)就會(huì)加載這個(gè).class文件讀取其中的二進(jìn)制指令,并且在內(nèi)存中構(gòu)造出對(duì)應(yīng)的類對(duì)象(在這個(gè)文件中是instance)。(形如Singleton.class)
由于類對(duì)象在一個(gè)Java進(jìn)程里,只是有唯一的一份,因此類對(duì)象內(nèi)部的類屬性也是唯一一份了。
如果不加static,
1.保證不了這個(gè)實(shí)例唯一
2.保證不了這個(gè)實(shí)例被創(chuàng)建的時(shí)機(jī)
3.讓當(dāng)前instance屬性是類屬性了。類屬性是長(zhǎng)在類對(duì)象上的,類對(duì)象又是唯一的實(shí)例(static保證了是在類加載的階段創(chuàng)建出一個(gè)實(shí)例)
(類加載:運(yùn)行一個(gè)java程序,就需要讓java進(jìn)程能夠找到并讀取對(duì)應(yīng)的.class文件就會(huì)讀取文件內(nèi)容,并解析,構(gòu)造成類對(duì)象.....這一系列的過(guò)程操作,稱為類加載。)
如果需要使用這個(gè)唯一實(shí)例,就需要通過(guò)Singleton.getInstance()方式來(lái)獲取。
同時(shí)為了避免Singleton類不小心被復(fù)制出多份來(lái),把構(gòu)造方法設(shè)為private,在類外就無(wú)法通過(guò)new的方式來(lái)創(chuàng)建這個(gè)Singleton實(shí)例了。
?
懶漢模式
如果拿吃完飯洗碗來(lái)分別比喻餓漢模式和單例模式,那么
餓漢模式:吃完飯后把所有的碗全部洗完,用了幾個(gè)就洗幾個(gè)
懶漢模式:吃完飯后不洗碗,下次吃飯前需要用多少個(gè)碗就洗多少個(gè)碗。
線程安全
上述寫(xiě)的餓漢模式和懶漢模式,如果在多線程環(huán)境下調(diào)用getInstance,是否是線程安全的?
結(jié)論就是餓漢模式是安全的,懶漢模式需要先看是否需要?jiǎng)?chuàng)建,再創(chuàng)建,涉及到了讀和寫(xiě)兩個(gè)操作。
如何讓?xiě)袧h模式成為是線程安全的呢?
加鎖
加鎖方式1:
加鎖方式2:
?
這樣也單例模式名字的由來(lái),只能有一個(gè)對(duì)象出現(xiàn),加鎖后t2線程就不會(huì)再重復(fù)創(chuàng)建對(duì)象。
但是到這里,當(dāng)前的代碼還是有問(wèn)題。
?所以:
如果對(duì)象還沒(méi)創(chuàng)建,才要加鎖
如果對(duì)象已經(jīng)創(chuàng)建,就不加鎖了
但是上述單例模式代碼還是有問(wèn)題,內(nèi)存可見(jiàn)性問(wèn)題。
instance = new Singleton();
可以拆分成三個(gè)步驟:
1.申請(qǐng)內(nèi)存空間
2.調(diào)用構(gòu)造方法,把這個(gè)內(nèi)存空間初始化成一個(gè)合理的對(duì)象
3.把內(nèi)存空間的地址賦值給instance引用
正常情況下是按照123這個(gè)順序來(lái)執(zhí)行的,但是編譯器可能是會(huì)對(duì)指令重排序,為了提高編程效率,調(diào)整代碼執(zhí)行順序。單線程中并沒(méi)有問(wèn)題,但是多線程環(huán)境下就會(huì)有問(wèn)題了。
解決辦法:volatile
1.解決內(nèi)存可見(jiàn)性
2.禁止指令重排序
?
?簡(jiǎn)單的單例模式就介紹到這~復(fù)雜的以后再說(shuō)~