4.7 併發下常見的Map面試題彙總

1、HashMap和HashTable的區別

1、HashMap線程不安全,HashTable線程安全

2、因爲線程安全,HashTable效率比HashMap低

3、HashTable的key和value都不能爲空,HashMap只能有一個key爲null,多個value值爲null

4、HashMap默認初始數組大小是16,HashTable默認是11,HashMap擴容2倍,HashTable擴大兩倍+1

5、HashMap需要重新計算hash值,而HashTable直接使用兌現過的hashCode

2、ConcurrentHashMap和HashTable在線程同步上有什麼區別?

HashTable直接使用的synchronized關鍵字

ConcurrentHashMap在jdk7中採用了Segment分段鎖,在jdk8中採用了CAS+synchronized,也採用了分段鎖的方式大大縮小了鎖的粒度,所有ConcurrentHashMap效率比HashTable高

3、hashMap和ConcurrentHashMap的區別

1、ConcurrentHashMap是線程安全的

2、HashMap的key和value都可以爲null,ConcurrentHashMap的key和value都不能爲null

3、紅黑樹相關的節點類,數據結構不同

4、爲什麼 ConcurrentHashMap  HashTable 效率要高?

1、HashTable 使用一把鎖(鎖住整個鏈表結構)處理併發問題,多個線程競爭一把鎖,容易阻塞;

2、ConcurrentHashMap 在JDK 1.7 中使用分段鎖(ReentrantLock + Segment + HashEntry),相當於把一個 HashMap 分成多個段,每段分配一把鎖,這樣支持多線程訪問。鎖粒度:基於 Segment,包含多個 HashEntry。

JDK 1.8 中使用 CAS + synchronized + Node + 紅黑樹。鎖粒度:Node(首結點)(實現 Map.Entry<K,V>)。鎖粒度降低了。

5、針對 ConcurrentHashMap 鎖機制具體分析(JDK 1.7 VS JDK 1.8)?

在1.7中,採用分段鎖機制,底層採用數組+鏈表結構

 

JDK 1.8 中,採用Node + CAS + Synchronized來保證併發安全。取消類 Segment,直接用 table 數組存儲鍵值對;當鏈表長度》=8,鏈表轉換爲紅黑樹,提升性能。底層變更爲數組 + 鏈表 + 紅黑樹。當紅黑樹<=6,降級爲鏈表

 

6、ConcurrentHashMap JDK 1.8 中,爲什麼要使用內置鎖 synchronized 來代替重入鎖 ReentrantLock

1、因爲jdk8對synchronized進行了大量優化,效率提升了

2、在大量的數據操作下,對於 JVM 的內存壓力,基於 API  的 ReentrantLock 會開銷更多的內存。

7、ConcurrentHashMap 簡單介紹?

重要的常量:

private transient volatile int sizeCtl;

負數 正在初始化或者擴容操作
-1 正在初始化
-N 代表有N-1個線程正在進行擴容操作
0默認值 代表還沒有被初始化
正數 表示初始化大小或者Map中的元素叨叨這個數量是,需要進行擴容了

數據結構:

Node 是存儲結構的基本單元,繼承 HashMap 中的 Entry,用於存儲數據;

TreeNode 繼承 Node,但是數據結構換成了二叉樹結構,是紅黑樹的存儲結構,用於紅黑樹中存儲數據;

TreeBin 是封裝 TreeNode 的容器,提供轉換紅黑樹的一些條件和鎖的控制。

存儲對象時(put() 方法):

1.如果沒有初始化,就調用 initTable() 方法來進行初始化;

2.如果沒有 hash 衝突就直接 CAS 無鎖插入;

3.如果需要擴容,就先進行擴容;

4.如果存在 hash 衝突,就加鎖來保證線程安全,兩種情況:一種是鏈表形式就直接遍歷到尾端插入,一種是紅黑樹就按照紅黑樹結構插入;

5.如果該鏈表的數量大於閥值 8,就要先轉換成紅黑樹的結構,break 再一次進入循環

6.如果添加成功就調用 addCount() 方法統計 size,並且檢查是否需要擴容。

擴容方法 transfer():

默認容量爲 16,擴容時,容量變爲原來的兩倍。

獲取對象時(get()方法):

1.計算 hash 值,定位到該 table 索引位置,如果是首結點符合就返回;

2.如果遇到擴容時,會調用標記正在擴容結點 ForwardingNode.find()方法,查找該結點,匹配就返回;

3.以上都不符合的話,就往下遍歷結點,匹配就返回,否則最後就返回 null。

8、ConcurrentHashMap 的併發度是什麼?

1.7中程序運行時能夠同時更新 ConccurentHashMap 且不產生鎖競爭的最大線程數。即Segment數組的長度,默認爲 16,且可以在構造函數中設置。當用戶設置併發度時,ConcurrentHashMap 會使用大於等於該值的最小2冪指數作爲實際併發度(假如用戶設置併發度爲17,實際併發度則爲32)。

1.8中併發度則無太大的實際意義了,主要用處就是當設置的初始容量小於併發度,將初始容量提升至併發度大小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章