來次面試吧?準備好沒,GO!java
程序員
- 問:自我介紹下吧。(開個玩笑。。。往下)請問你用過單例模式嗎?什麼是單例?
- 答:用過啊,單例模式就是隻建立一個實例。
- 問:噢?那是單線程,仍是多線程下都是呢?
- 答:這個類在JVM裏就一個實例(這樣回答也許會更好)
- (注:一般面試官,到這裏,就會讓你寫一個單例,固然咱們不,你看這篇文章,就是不讓你再網上找其餘重複的資料了。)
- 問:說說你用的場景吧
- 答:........
- 問:說說單例的幾種類型?或者說什麼時候對實例的初始化?
- 答:........
- 問:畫過單例的類圖嗎?會畫嗎?
- 答:(須要嗎?)
- 問:寫個單例的實現吧?
類名:SingleTon面試
實例:uniqueInstance 簡稱ust吧。(這裏我插入一句編程規範:起名不要吝惜把實例表明的意思表達清楚,名字可稍微長點,這裏就是想偷懶) 編程
實現1:緩存
- public class Singleton{
- private final static Singleton ust = new Singleton();
- private Singleton() {}
- public static Singleton getInstance(){
- return ust;
- }
- }
注:這裏順便說明一下語法。一般final與static同時出現,習慣讓final在前多線程
分析: ide
1. 這裏須要加final嗎? 是的,由於java反射,能夠改變private描述的變量學習
2. 有書裏把這種方式稱爲餓漢單例模式(另外一個種叫懶漢單例),而且已經爲人所接受測試
3. 在多線程方面表現出了他優點,不須要擔憂方法重複裏延時建立帶來的原子性(這樣說難理解,其實就是出現兩個或多個實例)優化
4. 這個,不符合咱們習慣的 用到時再實例化的原則(不過這不要緊。。。)
看,其實你發現這仍是個不錯的單例,那麼其實有個最好的實現,最好的實現:
單元素的枚舉類型已經成爲Singleton的最佳實踐
即便面對複雜的序列化或者反射***,絕對防止屢次實例化,還有他的簡潔和優雅。
----好吧,面試結束了。 其實你對單例的理解仍是不錯的,並且你已經獲得了最好的答案,有興趣完全玩轉單例嗎,繼續聽我嘮叨。
咱們看看懶漢單例模式:
實現2:
- public class Singleton{
- // private final static Singleton ust = null;
- // 不應加final,這裏明顯有偷懶嫌疑,複製上面的例子,又測試不夠,之後儘可能避免相似問題。
- // 8月15日修正
- private static Singleton ust = null;
- private Singleton(){}
- public staic Singleton getInstance(){
- //建議null==ust的方式,能幫助更快的發現錯誤。
- //部分老程序員的習慣,其實許多IDE會發現些低級錯誤。
- if(ust==null){//A
- ust = new Singleton();//B
- }
- return ust;
- }
- }
分析:
1. 懶漢模式,作到了須要時建立實例
2. 他遇到了尷尬的問題,由於當兩個線程分開運行到A,而後進入了if塊,可能就建立了2個實例,草稿的是,你已經初始了一些數據。
改進一下:
實現3:
- public class Singleton{
- private volatile static Singleton ust;
- private Singleton(){}
- public staic Singleton getInstance(){
- synchronized(Singleton.class){
- if(ust==null){
- ust= new Singleton();
- }
- }
- return ust;
- }
- }
分析:
1. 若是你不理解synchronized 的位置,就不用單例模式這麼多寫法,不如學習基礎
2. volatile 確保ust被實例化後,多個線程正確處理。他失去了JVM必要的代碼優化,若是不是多線程,就不要用
3. 這個叫作 「雙檢查加鎖」,單例最後一種方式
綜合討論會:
- 小明: 單例目前一共談到懶漢和餓漢兩種,還有雙檢查加鎖,最好的應該是單元素的枚舉類型
- 小剛: 是的,回答了開頭說的幾種單例,那麼哪些場景應該用單例呢?
- 小明: 我知道,有線程池,緩存,處理偏好設置,註冊表,日誌對象等等
- 小剛: 對,我對java比較瞭解,我知道Runtime.getRuntime()。
- C(爲嗎我叫C):我知道有java.lang.reflect.Proxy類
- 小明:有什麼共同點呢,爲何用?是遵循對象儘可能少建立原則?
- C:這是什麼意思?
- 小剛:這很簡單,不過這說法有點問題。由於對象佔內存,有要形成垃圾回收,GC的時候JVM但是隻幹這個麻煩事
- 小明:是啊!
- 小剛:我想我知道,某些對象最好只有一個實例,多了會有問題產生。
- C:什麼問題?
- 小剛:好比緩存,你從哪一個實例裏拿緩存呢?
- 小明:是的啊。。。
結束討論會,總結一下吧。不,等等,還要補充兩句:
1. 單例模式定義:確保一個只有一個實例,並提供一個全局訪問點
2. 若是getInstance()方法對應用程序不會額外負擔,或者說影響不大,那寫成怎樣,其實沒太大所謂。可是若是頻繁運行,就要仔細考慮,由於一個同步,可能使得執行效率降低100倍
繼續總結,還差個UML圖呢,不妨在上個枚舉的例子吧,枚舉構造器默認私有嗎?
枚舉就算了,是否是默認構造器,本身研究下吧。。。呵呵
這回真總結了:
1. 單例,有懶漢,餓漢,雙檢查加鎖3種常見用法
2. 單例模式,是由於若是多了,會形成數據遺漏等麻煩
3. 最好的單例,單元素的枚舉類型
呵呵,其實,就這些,原本想先寫工廠的,由於去面試,遇到某些對單例瞭解比較淺,解釋起來費勁,因而先以單例開篇,請關注下篇工廠模式。
--51CTO首發