摘要:防止指令重排序防止時指令重排序導致其他線程獲取到未初始化完的對象。枚舉類默認枚舉實例的創建是線程安全的,所以不需要擔心線程安全的問題。
單例模式是23種GOF模式中最簡單,也是最經常出現的一種設計模式,也是面試官最常愛考的一種模式,為什么呢?
因為單例模式足夠簡單,編寫一個單例模式代碼幾分鐘就能搞定,所以設計模式中面試官通常會選取單例模式作為出題。
下面把單例模式分幾個點,分別說說哪些地方面試官能考你?
通常面試官會很籠統的問你,什么是單例模式?單例模式用來解決了什么痛點?沒有單例模式我們會怎么辦?單例模式他有什么缺點嗎?
單例模式是最簡單的設計模式之一,屬于創建型模式,它提供了一種創建對象的方式,確保只有單個對象被創建。這個設計模式主要目的是想在整個系統中只能出現類的一個實例,即一個類只有一個對象。
單例模式的解決的痛點就是節約資源,節省時間從兩個方面看:
1.由于頻繁使用的對象,可以省略創建對象所花費的時間,這對于那些重量級的對象而言,是很重要的.
2.因為不需要頻繁創建對象,我們的GC壓力也減輕了,而在GC中會有STW(stop the world),從這一方面也節約了GC的時間
單例模式的缺點:簡單的單例模式設計開發都比較簡單,但是復雜的單例模式需要考慮線程安全等并發問題,引入了部分復雜度。
擴展:從你的回答中能進行哪些擴展呢?我們談到了GC,有可能這時候就會問你GC,STW等知識。談缺點的時候談到了復雜的單例模式,
這個時候可能會問你讓你設計一個優秀的單例模式你會怎么設計,會怎么實現?
通常這里面試官會問你單例模式怎么設計,需要看重哪些方面?一般來說單例模式有哪些實現方式?
設計單例模式的時候一般需要考慮幾種因素:
-線程安全
-延遲加載
-代碼安全:如防止序列化攻擊,防止反射攻擊(防止反射進行私有方法調用)
-性能因素
一般來說,我們去網上百度去搜大概有7,8種實現,,下面列舉一下需要重點知道的
餓漢,懶漢(線程安全,線程非安全),雙重檢查(DCL)(重點),內部類,以及枚舉(重點),
擴展:我們上面說到了各個模式的實現,這個時候很有可能會叫你手寫各個模式的代碼。當然也有可能會問你線程安全,代碼安全等知識。
餓漢模式餓漢模式的代碼如下:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }
餓漢模式代碼比較簡單,對象在類中被定義為private static,通過getInstance(),通過java的classLoader機制保證了單例對象唯一。
擴展:
有可能會問instance什么時候被初始化?雙重檢查DCLSingleton類被加載的時候就會被初始化,java虛擬機規范雖然沒有強制性約束在什么時候開始類加載過程,但是對于類的初始化,虛擬機規范則嚴格規定了有且只有四種情況必須立即對類進行初始化,遇到new、getStatic、putStatic或invokeStatic這4條字節碼指令時,如果類沒有進行過初始化,則需要先觸發其初始化。 生成這4條指令最常見的java代碼場景是:1)使用new關鍵字實例化對象2)讀取一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)3)設置一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)4)調用一個類的靜態方法
class的生命周期?
class的生命周期一般來說會經歷加載、連接、初始化、使用、和卸載五個階段
class的加載機制
這里可以聊下classloader的雙親委派模型。
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
synchronized同步塊里面能夠保證只創建一個對象。但是通過在synchronized的外面增加一層判斷,就可以在對象一經創建以后,不再進入synchronized同步塊。這種方案不僅減小了鎖的粒度,保證了線程安全,性能方面也得到了大幅提升。
同時這里要注意一定要說volatile,這個很關鍵,volatile一般用于多線程的可見性,但是這里是用來防止指令重排序的。
擴展:
為什么需要volatile?volatile有什么用?首先要回答可見性,這個是毋庸質疑的,然后可能又會考到java內存模型。
防止指令重排序: 防止new Singleton時指令重排序導致其他線程獲取到未初始化完的對象。instance = new Singleton()這句,這并非是一個原子操作,事實上在 JVM 中這句話大概做了下面 3 件事情。1.給 instance 分配內存2.調用 Singleton 的構造函數來初始化成員變量3.將instance對象指向分配的內存空間(執行完這步 instance 就為非 null 了)
但是在 JVM 的即時編譯器中存在指令重排序的優化。也就是說上面的第二步和第三步的順序是不能保證的,最終的執行順序可能是 1-2-3 也可能是 1-3-2。如果是后者,則在 3 執行完畢、2 未執行之前,被線程二搶占了,這時 instance 已經是非 null 了(但卻沒有初始化),所以線程二會直接返回 instance,然后使用,然后報錯。
順便也可以說下volatie原理用內存屏障
講講synchronized和volatile的區別這里可以從synchroized能保證原子性,volatile不能保證說起,以及講下synchroized是重量級鎖,甚至可以所以下他和Lock的區別等等。
線程安全一般怎么實現的?互斥同步。如lock,synchroized
非阻塞同步。如cas。
不同步。如threadLocal,局部變量。
枚舉類public enum Singleton{ INSTANCE; }
默認枚舉實例的創建是線程安全的,所以不需要擔心線程安全的問題。同時他也是《Effective Java》中推薦的模式。最后通過枚舉類,他能自動避免序列化/反序列化攻擊,以及反射攻擊(枚舉類不能通過反射生成)。
總結單例模式雖然看起來簡單,但是設計的Java基礎知識非常多,如static修飾符、synchronized修飾符、volatile修飾符、enum等。這里的每一個知識點都可以變成面試官下手的考點,而單例只是作為一個引子,考到最后看你到底掌握了多少。看你的廣度和深度到底是怎么樣的。
如果這篇文章對你有幫助,想要了解更多。或者想要1對1的交流。請關注下方公眾號吧。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76415.html
摘要:面試時經常會問到關于單例設計模式,因為它能考察的知識點較多且在開發中經常用到。那我就來說一說我對于單例設計模式的一些淺見。還有另一種實現方法稱為懶漢式。但以上代碼會出現線程安全問題。 Java面試時經常會問到關于單例設計模式,因為它能考察的知識點較多且在開發中經常用到。那我就來說一說我對于單例設計模式的一些淺見。首先,在Java中,什么是單例呢?就是保證類在內存中只有一個對象。那么問題...
摘要:面試官要不你來手寫下單例模式唄候選者單例模式一般會有好幾種寫法候選者餓漢式簡單懶漢式在方法聲明時加鎖雙重檢驗加鎖進階懶漢式靜態內部類優雅懶漢式枚舉候選者所謂餓漢式指的就是還沒被用到,就直接初始化了對象。面試官:我看你的簡歷寫著熟悉常見的設計模式,要不你來簡單聊聊你熟悉哪幾個吧?候選者:常見的工廠模式、代理模式、模板方法模式、責任鏈模式、單例模式、包裝設計模式、策略模式等都是有所了解的候選者:...
摘要:到底什么是閉包這個問題在面試是時候經常都會被問,很多小白一聽就懵逼了,不知道如何回答好。上面這么說閉包是一種特殊的對象。閉包的注意事項通常,函數的作用域及其所有變量都會在函數執行結束后被銷毀。從而使用閉包模塊化代碼,減少全局變量的污染。 閉包,有人說它是一種設計理念,有人說所有的函數都是閉包。到底什么是閉包?這個問題在面試是時候經常都會被問,很多小白一聽就懵逼了,不知道如何回答好。這個...
摘要:顯而易見的,當這個是的時,就不存在內存泄漏的問題。這個我在第一期自定義如何有效保證內存泄漏問題已經說得很明白了。 零零碎碎的東西總是記不長久,僅僅學習別人的文章也只是他人咀嚼后留下的殘渣。無意中發現了這個每日一道面試題,想了想如果只是簡單地去思考,那么不僅會收效甚微,甚至難一點的題目自己可能都懶得去想,堅持不下來。所以不如把每一次的思考、理解以及別人的見解記錄下來。不僅加深自己的理解,更要激...
閱讀 3620·2021-09-30 09:59
閱讀 2229·2021-09-13 10:34
閱讀 576·2019-08-30 12:58
閱讀 1507·2019-08-29 18:42
閱讀 2198·2019-08-26 13:44
閱讀 2921·2019-08-23 18:12
閱讀 3320·2019-08-23 15:10
閱讀 1624·2019-08-23 14:37