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

2021-09-25 23:35:59 字數 2786 閱讀 3221

q:hashmap 和 hashtable 有什麼區別?

a:①、hashmap 是執行緒不安全的,hashtable 是執行緒安全的;

②、由於執行緒安全,所以 hashtable 的效率比不上 hashmap;

③、hashmap最多隻允許一條記錄的鍵為null,允許多條記錄的值為null,而 hashtable 不允許;

④、hashmap 預設初始化陣列的大小為16,hashtable 為 11,前者擴容時,擴大兩倍,後者擴大兩倍+1;

⑤、hashmap 需要重新計算 hash 值,而 hashtable 直接使用物件的 hashcode

q:hashmap & concurrenthashmap 的區別?

a:除了加鎖,原理上無太大區別。

另外,hashmap 的鍵值對允許有null,但是concurrenthashmap 都不允許。

在資料結構上,紅黑樹相關的節點類有不同。hashmap裡的treenode繼承自linkedhashmap.entry,而另一邊繼承自自己定義的 node

q:為什麼 concurrenthashmap 比 hashtable 效率要高?

a:hashtable 使用一把鎖(鎖住整個鍊錶結構)處理併發問題,多個執行緒競爭一把鎖,容易阻塞;

concurrenthashmap 用了分段鎖:

jdk 1.7 中使用reentrantlock + segment + hashentry,相當於把乙個 hashmap 分成多個段,每段分配一把鎖,這樣支援多執行緒訪問。鎖粒度:基於 segment,包含多個 hashentry。

jdk 1.8 中使用 cas + synchronized + node + 紅黑樹。鎖粒度:node(首結點)(實現 map.entry)。鎖粒度降低了。

q:針對 concurrenthashmap 鎖機制具體分析(jdk 1.7 vs jdk 1.8)?

a:jdk 1.7 中,採用分段鎖的機制,實現併發的更新操作,底層採用陣列+鍊錶的儲存結構,包括兩個核心靜態內部類 segment 和 hashentry。

①、segment 繼承 reentrantlock(重入鎖) 用來充當鎖的角色,每個 segment 物件守護每個雜湊對映表的若干個桶;

②、hashentry 用來封裝對映表的鍵-值對;

③、每個桶是由若干個 hashentry 物件鏈結起來的鍊錶。

jdk 1.8 中,採用node + cas + synchronized來保證併發安全。取消類 segment,直接用 table 陣列儲存鍵值對;當 hashentry 物件組成的鍊錶長度超過 treeify_threshold 時,鍊錶轉換為紅黑樹,提公升效能。底層變更為陣列 + 鍊錶 + 紅黑樹。

q:concurrenthashmap 在 jdk 1.8 中,為什麼要使用內建鎖 synchronized 來代替重入鎖 reentrantlock?

a:①、jvm 開發團隊在1.8中對 synchronized做了大量效能上的優化,而且基於 jvm 的 synchronized 優化空間更大,更加自然。

②、在大量的資料操作下,對於 jvm 的記憶體壓力,作為乙個類 的 reentrantlock 會開銷更多的記憶體。

q:concurrenthashmap 簡單介紹?

a:①、重要的常量:

private transient volatile int sizectl;

當為負數時,-1 表示正在初始化,-n 表示 n - 1 個執行緒正在進行擴容;

當為 0 時,表示 table 還沒有初始化;

當為其他正數時,表示初始化或者下一次進行擴容的大小。

②、資料結構:

node 是儲存結構的基本單元,繼承 hashmap 中的 entry,用於儲存資料;

treenode 繼承 node,但是資料結構換成了二叉樹結構,是紅黑樹的儲存結構,用於紅黑樹中儲存資料;

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

③、儲存物件時(put() 方法):

1.如果沒有初始化,就呼叫 inittable() 方法來進行初始化;

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

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

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

5.如果該鍊錶的數量大於閥值 8,就要先轉換成紅黑樹的結構,break 再一次進入迴圈

6.如果新增成功就呼叫 addcount() 方法統計 size,並且檢查是否需要擴容。

④、擴容方法 transfer():預設容量為 16,擴容時,容量變為原來的兩倍。

helptransfer():呼叫多個工作執行緒一起幫助進行擴容,這樣的效率就會更高。

⑤、獲取物件時(get()方法):

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

2.如果遇到擴容時,會呼叫標記正在擴容結點 forwardingnode.find()方法,查詢該結點,匹配就返回;

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

q:concurrenthashmap 的併發度是什麼?

a:1.7中程式執行時能夠同時更新 conccurenthashmap 且不產生鎖競爭的最大執行緒數。預設為 16,且可以在建構函式中設定。當使用者設定併發度時,concurrenthashmap 會使用大於等於該值的最小2冪指數作為實際併發度(假如使用者設定併發度為17,實際併發度則為32)。

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

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

1 hashmap執行緒不安全,hashtable執行緒安全 2 因為執行緒安全,hashtable效率比hashmap低 3 hashtable的key和value都不能為空,hashmap只能有乙個key為null,多個value值為null 4 hashmap預設初始陣列大小是16,hasht...

SQL常見面試題彙總

sql查詢較慢的原因以及改進方法 重要程度 五顆 1 沒有索引或者沒有用到索引 這是查詢慢最常見的問題,是程式設計的缺陷 create unique clustered nonclustered index index name on with index property n 說明 unique ...

常見面試題之MAP(一)

難度中等2137 給你乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 請你找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。示例 給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2...