一些ConcurrentHashMap面試題


下面是我收集的一些面試題:

JDK1.8中的ConcurrentHashMap是如何保證線程安全的?

## [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-u5Li8ZPS-1644594019827)(C:\Users\14470\Desktop\java筆記\java JUC\ConcurrentHashMap刨析.assets\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p6dV9zZXU=,size_16,color_FFFFFF,t_70-16444002074692.png)]
模板2:

  1. 儲存Map數據的數組時被volatile關鍵字修飾,一旦被修改,其他線程就可見修改。因為是數組存儲,所以只有改變數組內存值是才會觸發volatile的可見性
  2. 如果put操作時hash計算出的槽點內沒有值,采用自旋+CAS保證put一定成功,且不會覆蓋其他線程put的值
  3. 如果put操作時節點正在擴容,即發現槽點為轉移節點,會等待擴容完成后再進行put操作,保證擴容時老數組不會變化
  4. 對槽點進行操作時會鎖住槽點,保證只有當前線程能對槽點上的鏈表或紅黑樹進行操作
  5. 紅黑樹旋轉時會鎖住根節點,保證旋轉時線程安全

2.JDK7和JDK8中的ConcurrentHashMap不同點。

## [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PEX4gUyQ-1644594019828)(C:\Users\14470\Desktop\java筆記\java JUC\ConcurrentHashMap刨析.assets\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p6dV9zZXU=,size_16,color_FFFFFF,t_70.png)]

3.擴容期間在未遷移到的hash桶插入數據會發生什么?

答:只要插入的位置擴容線程還未遷移到,就可以插入,當遷移到該插入的位置時,就會阻塞等待插入操作完成再繼續遷移 。

4.1 正在遷移的hash桶遇到 get 操作會發生什么?

答:在擴容過程期間形成的 hn 和 ln鏈 是使用的類似於復制引用的方式,也就是說 ln 和 hn 鏈是復制出來的,而非原來的鏈表遷移過去的,所以原來 hash 桶上的鏈表並沒有受到影響,因此如果當前節點有數據,還沒遷移完成,此時不影響讀,能夠正常進行。

如果當前鏈表已經遷移完成,那么頭節點會被設置成fwd節點,此時get線程會幫助擴容。

4.2 正在遷移的hash桶遇到 put/remove 操作會發生什么?

如果當前鏈表已經遷移完成,那么頭節點會被設置成fwd節點,此時寫線程會幫助擴容,如果擴容沒有完成,當前鏈表的頭節點會被鎖住,所以寫線程會被阻塞,直到擴容完成。

5.如果 lastRun 節點正好在一條全部都為高位或者全部都為低位的鏈表上,會不會形成死循環?

答:在數組長度為64之前會導致一直擴容,但是到了64或者以上后就會轉換為紅黑樹,因此不會一直死循環 。

6.擴容后 ln 和 hn 鏈不用經過 hash 取模運算,分別被直接放置在新數組的 i 和 n + i 的位置上,那么如何保證這種方式依舊可以用過 h & (n - 1) 正確算出 hash 桶的位置?

答:如果 fh & n-1 = i ,那么擴容之后的 hash 計算方法應該是 fh & 2n-1 。 因為 n 是 2 的冪次方數,所以 如果 n=16, n-1 就是 1111(二進制), 那么 2n-1 就是 11111 (二進制) 。 其實 fh & 2n-1 和 fh & n-1 的值區別就在於多出來的那個 1 => fh & (10000) 這個就是兩個 hash 的區別所在 。而 10000 就是 n 。所以說 如果 fh 的第五 bit 不是 1 的話 fh & n = 0 => fh & 2n-1 == fh & n-1 = i 。 如果第5位是 1 的話 。fh & n = n => fh & 2n-1 = i+n 。

7.並發情況下,各線程中的數據可能不是最新的,那為什么 get 方法不需要加鎖?

答:get操作全程不需要加鎖是因為Node的成員val是用volatile修飾的,在多線程環境下線程A修改結點的val或者新增節點的時候是對線程B可見的。。

8.1 ConcurrentHashMap 和 Hashtable 的區別?

ConcurrentHashMap 和 Hashtable 的區別主要體現在實現線程安全的方式上不同。
底層數據結構
JDK1.7的 ConcurrentHashMap 底層采用 分段的數組+鏈表 實現,JDK1.8 采用的數據結構跟HashMap1.8的結構一樣,數組+鏈表/紅黑二叉樹。Hashtable是采用 數組+鏈表 的形式。
實現線程安全的方式(重要):

① 在JDK1.7的時候,ConcurrentHashMap(分段鎖) 對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器里不同數據段的數據,就不會存在鎖競爭,提高並發訪問率。 到了 JDK1.8 的時候已經摒棄了Segment的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,並發控制使用 synchronized 和 CAS 來操作。

② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另一個線程不能使用 put 添加元素,也不能使用 get,競爭會越來越激烈效率越低。

8.2 ConcurrentHashMap 和 HashMap 的相同點和不同點

相同之處:

都是數組 +鏈表+紅黑樹的數據結構(JDK8之后),所以基本操作的思想一致
都實現了Map接口,繼承了AbstractMap 操作類,所以方法大都相似,可以相互切換
不同之處:
ConcurrentHashMap 是線程安全的,多線程環境下,無需加鎖直接使用
ConcurrentHashMap 多了轉移節點,主要用戶保證擴容時的線程安全

9.擴容過程中,讀訪問能否訪問的到數據?怎么實現的?

可以的。當數組在擴容的時候,會對當前操作節點進行判斷,如果當前節點還沒有被設置成fwd節點,那就可以進行讀寫操作,如果該節點已經被處理了,那么當前線程也會加入到擴容的操作中去。

10.為什么超過沖突超過8才將鏈表轉為紅黑樹而不直接用紅黑樹?

默認使用鏈表, 鏈表占用的內存更小
正常情況下,想要達到沖突為8的幾率非常小,如果真的發生了轉為紅黑樹可以保證極端情況下的效率

11. ConcurrentHashMap 和HashMap的擴容有什么不同?

HashMap的擴容是創建一個新數組,將值直接放入新數組中,JDK7采用頭鏈接法,會出現死循環,JDK8采用尾鏈接法,不會造成死循環
ConcurrentHashMap 擴容是從數組隊尾開始拷貝,拷貝槽點時會鎖住槽點,拷貝完成后將槽點設置為轉移節點。所以槽點拷貝完成后將新數組賦值給容器

12. ConcurrentHashMap 是如何發現當前槽點正在擴容的?

ConcurrentHashMap 新增了一個節點類型,叫做轉移節點,當我們發現當前槽點是轉移節點時(轉移節點的 hash 值是 -1),即表示 Map 正在進行擴容.

13.描述一下 CAS 算法在 ConcurrentHashMap 中的應用

  • CAS是一種樂觀鎖,在執行操作時會判斷內存中的值是否和准備修改前獲取的值相同,如果相同,把新值賦值給對象,否則賦值失敗,整個過程都是原子性操作,無線程安全問題
  • ConcurrentHashMap 的put操作是結合自旋用到了CAS,如果hash計算出的位置的槽點值為空,就采用CAS+自旋進行賦值,如果賦值是檢查值為空,就賦值,如果不為空說明有其他線程先賦值了,放棄本次操作,進入下一輪循環

1、ConcurrentHashMap有哪些構造函數?

一共有五個,

2、ConcurrentHashMap使用什么技術來保證線程安全?

jdk1.7:Segment+HashEntry來進行實現的;

jdk1.8:放棄了Segment臃腫的設計,采用Node+CAS+Synchronized來保證線程安全;

3、ConcurrentHashMap的get方法是否要加鎖,為什么?

不需要,get方法采用了unsafe方法,來保證線程安全。

4、ConcurrentHashMap迭代器是強一致性還是弱一致性?HashMap呢?

弱一致性,hashmap強一直性。

ConcurrentHashMap可以支持在迭代過程中,向map添加新元素,而HashMap則拋出了ConcurrentModificationException,

因為HashMap包含一個修改計數器,當你調用他的next()方法來獲取下一個元素時,迭代器將會用到這個計數器。

5、ConcurrentHashMap1.7和1.8的區別:

jdk1.8的實現降低鎖的粒度,jdk1.7鎖的粒度是基於Segment的,包含多個HashEntry,而jdk1.8鎖的粒度就是Node

數據結構:jdk1.7 Segment+HashEntry;jdk1.8 數組+鏈表+紅黑樹+CAS+synchronized
6、


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM