天天看點

單例模式

單例模式也叫單子模式,屬于建立型模式。

單例模式可分為飽漢(懶漢)式單例和饑漢(餓漢)式單例兩種。

單例設計模式是一種非常常見的設計模式,如果整個系統中允許某個類隻存在唯一執行個體,那麼就可以使用單例模式。

特别是:

1.初始化這個執行個體需要加載比較重的資源;

2.該執行個體要被頻繁調用;

3.系統允許隻有一個唯一執行個體;

那麼,原則上必須使用單例模式。

單例模式看上去非常簡單,但是在飽漢(懶漢)式單例模式的使用中,需要留意線程不同步和不同寫法的代碼在編譯過程産生的單例bug,饑漢(餓漢)式單例則不存在這個問題。

該寫法由google工程師bob lee發明,屬于懶漢單例模式。解決了飽漢單例模式兩大難題。

public class singletonclass{

private singletonclass(){} ;

private static class singletonclassinstance{

private static final singletonclass instance = new singletonclass() ;

}

public static singletonclass getinstance(){

return singletonclassinstance.instance ;

1.餓漢式單例模式:

private static singletonclass instance = new singletonclass() ;

return instance ;

看代碼,這個執行個體是靜态的,且在系統初始化的時候就已經初始化,并且永久存在。這就是餓漢式單例。因為是系統初始化的時候就存在,是以該執行個體不會因為線程的排程産生,是以不會存線上程安全問題。并且代碼結構簡約嚴謹,不會因為編譯過程中的代碼調優而改變代碼的執行順序,是以也不會産生編譯bug。

下面看飽漢式單例的舉例,我們通常所說的惰性加載(lazy load),程式初始化的時候單例執行個體并不初始化,需要等線程調用的時候才初始化這個執行個體。

2.飽漢式單例模式:

private static singletonclass instance = null ;

if(instance == null){

instance = new singletonclass() ;

在多線程環境中,cpu發生時間片切換,兩個或多個線程有可能幾乎是同一時間執行的,那麼,這個執行個體同時被認為是null,就會多次被建立,雖然可能對性能的影響微乎其微,但是已經違反了單子模式的設計初衷。

如何既要使用懶漢式單例模式,又要保證線程安全?很多蹩腳的程式員自然想到了使用線程阻塞(synchronized關鍵字)。這很可笑,synchronized本來就對性能有很大影響,還有必要使用懶漢式單例嗎?

下面我們給懶漢式單例加個鎖:

public synchronized static singletonclass getinstance(){

這樣性能不好,換個好點的加鎖方式:

synchronized(singletonclass.class){

看上去性能好像好多了,但是還是不夠好:

這樣看上去完美了。這就是雙鎖實作單子模式。

枚舉

public enum singleton2 {

instance ;

public void whatevermethod(){

 這種方式是effective java作者josh bloch 提倡的方式,它不僅能避免多線程同步問題,而且還能防止反序列化重新建立新的對象,可謂是很堅強的壁壘啊,不過,個人認為由于1.5中才加入enum特性,用這種方式寫不免讓人感覺生疏,在實際工作中,我也很少看見有人這麼寫過。