1. 程式人生 > 其它 >【面試普通人VS高手系列】ConcurrentHashMap 底層具體實現知道嗎?實現原理是什麼?

【面試普通人VS高手系列】ConcurrentHashMap 底層具體實現知道嗎?實現原理是什麼?

之前分享過一期HashMap的面試題,然後有個小夥伴私信我說,他遇到了一個ConcurrentHashMap的問題不知道怎麼回答。
於是,就有了這一期的內容!!
我是Mic,一個工作了14年的Java程式設計師,今天我來分享關於 ”ConcurrentHashMap 底層實現原理“ 這個問題,
看看普通人和高手是如何回答的!

普通人:

嗯.. ConcurrentHashMap是用陣列和連結串列的方式來實現的,嗯… 在JDK1.8裡面還引入了紅黑樹。然後連結串列和紅黑樹是解決hash衝突的。嗯……

高手:

這個問題我從這三個方面來回答:

  1. ConcurrentHashMap的整體架構
  2. ConcurrentHashMap的基本功能
  3. ConcurrentHashMap在效能方面的優化
  • ConcurrentHashMap的整體架構


    這個是ConcurrentHashMap在JDK1.8中的儲存結構,它是由陣列、單向連結串列、紅黑樹組成。

    當我們初始化一個ConcurrentHashMap例項時,預設會初始化一個長度為16的陣列。由於ConcurrentHashMap它的核心仍然是hash表,所以必然會存在hash衝突問題。

    ConcurrentHashMap採用鏈式定址法來解決hash衝突。

    當hash衝突比較多的時候,會造成連結串列長度較長,這種情況會使得ConcurrentHashMap中資料元素的查詢複雜度變成O(n

    )。因此在JDK1.8中,引入了紅黑樹的機制。

    當陣列長度大於64並且連結串列長度大於等於8的時候,單項鍊表就會轉換為紅黑樹。

    另外,隨著ConcurrentHashMap的動態擴容,一旦連結串列長度小於8,紅黑樹會退化成單向連結串列。

  • ConcurrentHashMap的基本功能

    ConcurrentHashMap本質上是一個HashMap,因此功能和HashMap一樣,但是ConcurrentHashMap在HashMap的基礎上,提供了併發安全的實現。

    併發安全的主要實現是通過對指定的Node節點加鎖,來保證資料更新的安全性。

  • ConcurrentHashMap在效能方面做的優化

    如果在併發效能和資料安全性之間做好平衡,在很多地方都有類似的設計,比如cpu的三級快取、mysql的buffer_pool、Synchronized的鎖升級等等。

    ConcurrentHashMap也做了類似的優化,主要體現在以下幾個方面:

    • 在JDK1.8中,ConcurrentHashMap鎖的粒度是陣列中的某一個節點,而在JDK1.7,鎖定的是Segment,鎖的範圍要更大,因此效能上會更低。

    • 引入紅黑樹,降低了資料查詢的時間複雜度,紅黑樹的時間複雜度是O(logn)。

    • 當陣列長度不夠時,ConcurrentHashMap需要對陣列進行擴容,在擴容的實現上,ConcurrentHashMap引入了多執行緒併發擴容的機制,簡單來說就是多個執行緒對原始陣列進行分片後,每個執行緒負責一個分片的資料遷移,從而提升了擴容過程中資料遷移的效率。

    • ConcurrentHashMap中有一個size()方法來獲取總的元素個數,而在多執行緒併發場景中,在保證原子性的前提下來實現元素個數的累加,效能是非常低的。ConcurrentHashMap在這個方面的優化主要體現在兩個點:

      • 當執行緒競爭不激烈時,直接採用CAS來實現元素個數的原子遞增。
      • 如果執行緒競爭激烈,使用一個數組來維護元素個數,如果要增加總的元素個數,則直接從陣列中隨機選擇一個,再通過CAS實現原子遞增。它的核心思想是引入了陣列來實現對併發更新的負載。

以上就是我對這個問題的理解!

總結

從高手的回答中可以看到,ConcurrentHashMap裡面有很多設計思想值得學習和借鑑。

比如鎖粒度控制、分段鎖的設計等,它們都可以應用在實際業務場景中。

很多時候大家會認為這種面試題毫無價值,當你有足夠的積累之後,你會發現從這些技術底層的設計思想中能夠獲得很多設計思路。

本期的普通人VS高手面試系列就到這裡結束了,喜歡的朋友記得點贊收藏。

部分高手面試文件已整理,需要的小夥伴可以私信或者評論區留言。

另外,我也陸續收到了很多小夥伴的面試題,我會在後續的內容中逐步更新給到大家!