單例模式的DCL方式,您不可不知道的知識點
最近參加了騰訊音樂Android工程師崗位的面試,這裡憑記憶記錄了面試中的一些考點,希望能幫到正在面試的你(答案還在整理中)!
1、Java呼叫函式傳入實際引數時,是值傳遞還是引用傳遞?
2、單例模式的DCL方式,為什麼需要第二次判空?
單例模式的DCL是一種比較好的單例實現方式,面試中被問及的頻率非常高,考察的方式也多種多樣。根據本題的提問,這裡簡單整理了一下,這裡面的每一個點最好都能夠做到爛熟於心:
1 public class Test { 2 private volatile static Test instance; 3 4 private Test() { 5 6 } 7 8 public static Test getInstance() { 9 if (instance == null) { 10 synchronized (Test.class) { 11 if (instance == null) { 12 instance = new Test(); 13 } 14 } 15 } 16 return instance; 17 } 18 }
這裡有5個要點需要注意:
(1)第一個注意點:使用私有的建構函式,確保正常情況下該類不能被外部初始化(非正常情況比如通過反射初始化,一般使用反射之後單例模式也就失去效果了)。
(2)第二個注意點:getInstance方法中第一個判空條件,邏輯上是可以去除的,去除之後並不影響單例的正確性,但是去除之後效率低。因為去掉之後,不管instance是否已經初始化,都會進行synchronized操作,而synchronized是一個重操作消耗效能。加上之後,如果已經初始化直接返回結果,不會進行synchronized操作。
(3)第三個注意點:加上synchronized是為了防止多個執行緒同時呼叫getInstance方法時,各初始化instance一遍的併發問題。
(4)第四個注意點:getInstance方法中的第二個判空條件是不可以去除,如果去除了,並且剛好有兩個執行緒a和b都通過了第一個判空條件。此時假設a先獲得鎖,進入synchronized的程式碼塊,初始化instance,a釋放鎖。接著b獲得鎖,進入synchronized的程式碼塊,也直接初始化instance,instance被初始化多遍不符合單例模式的要求~。加上第二個判空條件之後,b獲得鎖進入synchronized的程式碼塊,此時instance不為空,不執行初始化操作。
(5)第五個注意點:instance的宣告有一個voliate關鍵字,如果不用該關鍵字,有可能會出現異常。因為instance = new Test();並不是一個原子操作,會被編譯成三條指令,如下所示。
1)給Test的例項分配記憶體
2)初始化Test的構造器
3)將instance物件指向分配的記憶體空間(注意,此時instance就不為空)
然後咧,java會指令重排序,JVM根據處理器的特性,充分利用多級快取,多核等進行適當的指令重排序,使程式在保證業務執行的同時,充分利用CPU的執行特點,最大的發揮機器的效能!簡單來說就是jvm執行上面三條指令的時候,不一定是1-2-3這樣執行,有可能是1-3-2這樣執行。如果jvm是按照1-3-2來執行的話,當1-3執行完2還沒執行的時候,如果另外一個執行緒呼叫getInstance(),因為3執行了此時instance不為空,直接返回instance。問題是2還沒執行,此時instance相當於什麼都沒有,肯定是有問題的。然後咧,voliate有一個特性就是禁止指令重排序,上面的三條指令是按照1-2-3執行的,這樣就沒有問題了。
參考:https://blog.csdn.net/hnd978142833/article/details/81633730
3、volatile有什麼作用?AtomiticInteger有什麼作用,底層實現原理是什麼?與synchronized關鍵字有什麼區別?cas有什麼弊端?
關於多執行緒相關的知識點,volatile、AtomiticInteger、synchronized、cas問題都是高頻考點,與之相關的知識點如:重量級鎖/輕量級鎖、樂觀鎖/悲觀鎖、JMM(Java Memmory Mode Java記憶體模型)、使用者空間/核心空間、多執行緒三要素(原子性、可見性、順序性)、自旋、ABA問題等,都是需要掌握的要點。
推薦閱讀:【死磕Synchronized底層實現】
【面試官沒想到,volatile能吹上半個小時】
【《吊打面試官》系列-樂觀鎖、悲觀鎖】
【「每日知識點」什麼是 CAS 機制】
4、Android Log中的tag,用類名.class.getSimpleName()來獲取,會有什麼弊端?
5、反射有什麼作用?有什麼弊端?
6、廣播底層實現機制?為什麼會比AIDL方式慢?與EventBus相比有什麼區別?
7、Handler如何保證每個執行緒只有一個looper?ThreadLocal有什麼作用?
這道題其實主要考察ThreadLocal,不瞭解ThreadLocal的可以閱讀博文:【朝花夕拾】Android多執行緒之(二)ThreadLocal篇,以及【再有人問你什麼是ThreadLocal,就把這篇文章甩給他!】
8、100個0~100之間的整數,實現排序
9、RxJava介紹
10、Glide介紹
11、measuredWidth和width的區別
結論:getMeasuredWidth()獲取的是view原始的大小,也就是這個view在XML檔案中配置或者是程式碼中設定的大小。getWidth()獲取的是這個view最終顯示的大小,這個大小有可能等於原始的大小也有可能不等於原始大小。
推薦閱讀:【android中getWidth()和getMeasuredWidth()之間的區別】
12、SparseArray介紹,為什麼能提高效能
13、MVP與MVVM的區別,MVVM的實現方式
14、分享時,Android N開始對url做了什麼限制?
15、HashSet介紹
16、軟引用和弱引用的區別,什麼時候會GC?System.gc()的時候系統會立即回收系統垃圾嗎?
17、Exception和Error有什麼區別?Error能被捕捉嗎?OOM Error能被捕捉嗎?
18、Sharepreference commit()和apply()的區別。Sharepreference程序安全嗎?執行緒安全嗎?
19、500x500的png圖片所佔的記憶體大小。同一張圖片在xxdpi-drawable和drawable中誰佔用的記憶體更大,大多少?
20、RecyclerView與ListView的區別。
大體上這記得麼多,面試官會根據回答的內容進一步深入提問,讀者可以在該知識點上進一步拓