併發環境下延遲加載Singleton實例的終極方案:Initialization-on-demand holder idiom

相信你對這個問題已經很熟悉了:併發環境下如何延遲加載Singleton Instance ? 

Java代碼  收藏代碼
  1. public class Expensive {  
  2.     private static Expensive instance;  
  3.     private Expensive(){}
  4.     public static Expensive getInstance() {  
  5.         if (instance == null) {  
  6.             instance = new Expensive();  
  7.         }  
  8.         return instance;  
  9.     }  
  10. }  


如果getInstance()處不使用synchronzied, 可能導致產生兩個singleton對象, 或者拿到半殘的instance對象。至於臭名昭著的DCL,那就更不必說了。 

如果用synchronized, 那可能因爲鎖的原因在高併發下使性能受損。 

最後一招似乎是不使用延遲加載,而是在類初始化時主動生成instance對象; 但是,如果生成這個對象確實很昂貴,而且又很有可能確實用不上它,那主動初始化豈不是很浪費? 

《Java併發編程實踐》給出了致命一招:Initialization-on-demand holder,即把instance的初始化投入到一個內部類的初始過程中,就可以兼顧正確性和性能。 
  1. 內部類的初始化是延遲的,外部類初始化時不會初始化內部類。 
  2. 內部類的初始化是線程安全的,所以不用擔心兩個instance或半殘instance的問題。 
  3. 第一次獲取instance需要等它初始化,以後再獲取就不必了,而且也不需要鎖。所以在性能上也是妥妥的。 

Java代碼  收藏代碼
  1. public class Expensive {  
  2.    private Expensive(){}
  3.     private static class LazyHolder {  
  4.         private static final Expensive instance = new Expensive();  
  5.     }  
  6.   
  7.     public static Expensive getInstance() {  
  8.         return LazyHolder.instance;  
  9.     }  
  10. }  



更多介紹:http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
發佈了48 篇原創文章 · 獲贊 3 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章