高性能單例模式

轉載 http://blog.csdn.net/generalfu/article/details/8142463

面試的時候,常常會被問到這樣一個問題:請您寫出一個單例模式(Singleton Pattern)吧。好吧,寫就寫,這還不容易。順手寫一個:

public final class EagerSingleton     
{     
    private static EagerSingleton singObj = new EagerSingleton();     

    private EagerSingleton(){     
    }     

    public static EagerSingleton getSingleInstance(){     
       return singObj;   
    }     
}    

這種寫法就是所謂的飢餓模式(Singleton Pattern),每個對象在沒有使用之前就已經初始化了。這就可能帶來潛在的性能問題:如果這個對象很大呢?沒有使用這個對象之前,就把它加載到了內存中去是一種巨大的浪費。針對這種情況,我們可以對以上的代碼進行改進,使用一種新的設計思想——延遲加載(Lazy-load Singleton)

public final class LazySingleton     
{     
    private static LazySingleton singObj = null;     

    private LazySingleton(){     
    }     

    public static LazySingleton getSingleInstance(){     
        if(null == singObj ) singObj = new LazySingleton();   
          return singObj;   
    }     
}   

這種寫法就是所謂的飢餓模式(Singleton Pattern)。它使用了延遲加載來保證對象在沒有使用之前,是不會進行初始化的。但是,通常這個時候面試官又會提問新的問題來刁難一下。他會問:這種寫法線程安全嗎?回答必然是:不安全。這是因爲在多個線程可能同時運行到第九行,判斷singObj爲null,於是同時進行了初始化。所以,這是面臨的問題是如何使得這個代碼線程安全?很簡單,在那個方法前面加一個Synchronized就OK了。

public final class ThreadSafeSingleton     
{     
    private static ThreadSafeSingleton singObj = null;     

    private ThreadSafeSingleton(){     
    }     

    public static Synchronized ThreadSafeSingleton getSingleInstance(){     
        if(null == singObj ) singObj = new ThreadSafeSingleton();   
            return singObj;   
    }     
}     

寫到這裏,面試官可能仍然會狡猾的看了你一眼,繼續刁難到:這個寫法有沒有什麼性能問題呢?答案肯定是有的!同步的代價必然會一定程度的使程序的併發度降低(Singleton Pattern)。那麼有沒有什麼方法,一方面是線程安全的,有可以有很高的併發度呢?我們觀察到,線程不安全的原因其實是在初始化對象的時候,所以,可以想辦法把同步的粒度降低,只在初始化對象的時候進行同步。這裏有必要提出一種新的設計思想——雙重檢查鎖(Double-Checked Lock)

public final class DoubleCheckedSingleton     
{     
    private static DoubleCheckedSingletonsingObj = null;     

    private DoubleCheckedSingleton(){     
    }     

    public static DoubleCheckedSingleton getSingleInstance(){     
        if(null == singObj ) {   
              Synchronized(DoubleCheckedSingleton.class){   
                     if(null == singObj)   
                           singObj = new DoubleCheckedSingleton();   
              }   
         }   
       return singObj;   
    }     
}    

這種寫法使得只有在加載新的對象進行同步,在加載完了之後,其他線程在第九行就可以判斷跳過鎖的的代價直接到第15行代碼了。做到很好的併發度。

發佈了35 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章