我是架構師--設計模式-單例模式

 

   來次面試吧?準備好沒,GO!java

 程序員

  1.    問:自我介紹下吧。(開個玩笑。。。往下)請問你用過單例模式嗎?什麼是單例?  
  2. 答:用過啊,單例模式就是隻建立一個實例。  
  3.    問:噢?那是單線程,仍是多線程下都是呢?  
  4. 答:這個類在JVM裏就一個實例(這樣回答也許會更好)  
  5.    (注:一般面試官,到這裏,就會讓你寫一個單例,固然咱們不,你看這篇文章,就是不讓你再網上找其餘重複的資料了。)  
  6.    問:說說你用的場景吧  
  7. 答:........  
  8.    問:說說單例的幾種類型?或者說什麼時候對實例的初始化?  
  9. 答:........  
  10.    問:畫過單例的類圖嗎?會畫嗎?  
  11. 答:(須要嗎?)  
  12.    問:寫個單例的實現吧?  

 類名:SingleTon面試

 實例:uniqueInstance 簡稱ust吧。(這裏我插入一句編程規範:起名不要吝惜把實例表明的意思表達清楚,名字可稍微長點,這裏就是想偷懶) 編程

實現1:緩存

  
  
  
  
  1. public class Singleton{  
  2.   private final static Singleton ust = new Singleton();  
  3.   private Singleton() {}  
  4.   public static Singleton getInstance(){  
  5.      return ust;  
  6.   }  
  7. }  

注:這裏順便說明一下語法。一般final與static同時出現,習慣讓final在前多線程

分析: ide

1. 這裏須要加final嗎? 是的,由於java反射,能夠改變private描述的變量學習

2. 有書裏把這種方式稱爲餓漢單例模式(另外一個種叫懶漢單例),而且已經爲人所接受測試

3. 在多線程方面表現出了他優點,不須要擔憂方法重複裏延時建立帶來的原子性(這樣說難理解,其實就是出現兩個或多個實例)優化

4. 這個,不符合咱們習慣的 用到時再實例化的原則(不過這不要緊。。。)

 看,其實你發現這仍是個不錯的單例,那麼其實有個最好的實現,最好的實現:

單元素的枚舉類型已經成爲Singleton的最佳實踐

即便面對複雜的序列化或者反射***,絕對防止屢次實例化,還有他的簡潔和優雅。

 ----好吧,面試結束了。 其實你對單例的理解仍是不錯的,並且你已經獲得了最好的答案,有興趣完全玩轉單例嗎,繼續聽我嘮叨。


    咱們看看懶漢單例模式:

實現2:

  
  
  
  
  1. public class Singleton{  
  2.     // private final static Singleton ust = null;
  3. // 不應加final,這裏明顯有偷懶嫌疑,複製上面的例子,又測試不夠,之後儘可能避免相似問題。
  4. // 8月15日修正
  5. private static Singleton ust = null;
  6.      private Singleton(){}  
  7.      public staic Singleton getInstance(){  
  8. //建議null==ust的方式,能幫助更快的發現錯誤。
  9. //部分老程序員的習慣,其實許多IDE會發現些低級錯誤。  
  10.         if(ust==null){//A  
  11.              ust = new Singleton();//B  
  12.          }  
  13.        return ust;  
  14.      }  
  15. }   

分析:

1. 懶漢模式,作到了須要時建立實例

2. 他遇到了尷尬的問題,由於當兩個線程分開運行到A,而後進入了if塊,可能就建立了2個實例,草稿的是,你已經初始了一些數據。 

改進一下:

實現3: 

  
  
  
  
  1. public class Singleton{  
  2. private volatile static Singleton ust;  
  3. private Singleton(){}  
  4. public staic Singleton getInstance(){  
  5. synchronized(Singleton.class){  
  6.    if(ust==null){  
  7.     ustnew Singleton();  
  8.    }  
  9.  }  
  10. return ust;  
  11. }  
  12. }  

 分析:

  1. 若是你不理解synchronized 的位置,就不用單例模式這麼多寫法,不如學習基礎

  2. volatile 確保ust被實例化後,多個線程正確處理。他失去了JVM必要的代碼優化,若是不是多線程,就不要用

   3. 這個叫作 「雙檢查加鎖」,單例最後一種方式


綜合討論會: 

  
  
  
  
  1. 小明: 單例目前一共談到懶漢和餓漢兩種,還有雙檢查加鎖,最好的應該是單元素的枚舉類型  
  2. 小剛: 是的,回答了開頭說的幾種單例,那麼哪些場景應該用單例呢?  
  3. 小明: 我知道,有線程池,緩存,處理偏好設置,註冊表,日誌對象等等  
  4. 小剛: 對,我對java比較瞭解,我知道Runtime.getRuntime()。   
  5. C(爲嗎我叫C):我知道有java.lang.reflect.Proxy類   
  6. 小明:有什麼共同點呢,爲何用?是遵循對象儘可能少建立原則? 
  7. C:這是什麼意思?   
  8. 小剛:這很簡單,不過這說法有點問題。由於對象佔內存,有要形成垃圾回收,GC的時候JVM但是隻幹這個麻煩事  
  9. 小明:是啊 
  10. 小剛:我想我知道,某些對象最好只有一個實例,多了會有問題產生。   
  11. C:什麼問題?   
  12. 小剛:好比緩存,你從哪一個實例裏拿緩存呢?   
  13. 小明:是的啊。。。  

結束討論會,總結一下吧。不,等等,還要補充兩句:
1. 單例模式定義:確保一個只有一個實例,並提供一個全局訪問點

2. 若是getInstance()方法對應用程序不會額外負擔,或者說影響不大,那寫成怎樣,其實沒太大所謂。可是若是頻繁運行,就要仔細考慮,由於一個同步,可能使得執行效率降低100倍

 

繼續總結,還差個UML圖呢,不妨在上個枚舉的例子吧,枚舉構造器默認私有嗎? 

p_w_picpath 


枚舉就算了,是否是默認構造器,本身研究下吧。。。呵呵

這回真總結了:
1. 單例,有懶漢,餓漢,雙檢查加鎖3種常見用法
2. 單例模式,是由於若是多了,會形成數據遺漏等麻煩
3. 最好的單例,單元素的枚舉類型

 呵呵,其實,就這些,原本想先寫工廠的,由於去面試,遇到某些對單例瞭解比較淺,解釋起來費勁,因而先以單例開篇,請關注下篇工廠模式。

--51CTO首發

相關文章
相關標籤/搜索