1. 程式人生 > >單例模式的DCL方式,您不可不知道的知識點

單例模式的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的區別。

大體上這記得麼多,面試官會根據回答的內容進一步深入提問,讀者可以在該知識點上進一步拓