JDK1.8-ConcurrentHashMap的 rehash 擴容邏輯

前言

此乃隨筆, 用於記錄ConcurrentHashMap的擴容邏輯, 這位大神 JDK1.8–深度分析CONCURRENTHASHMAP原理分析 的文章給了我莫大的鼓勵。

順帶, 記錄了HashMap的擴容細則。

至今爲止, 我依舊沒懂 ConcurrentHashMap 的擴容細則。

ConcurrentHashMap resize/rehash

1. 什麼時候resize

跟HashMap一樣, 使用Node數組, 數組有大小Capacity;
數組元素上掛Node結點, 可以是單鏈表(不過8位), 可以是紅黑樹。
.
因爲是併發HashMap, 沒有size字段(即時統計)。
加載因子loadFactor, 1.8已經不再使用。

  1. 每個Node結點的長度> 8時;
    1. 如果數組大小< 64, 優先擴容resize(rehash)
    2. 大於64,優先轉紅黑樹。轉時鎖邏輯與put鎖邏輯一致。
  2. ConcurrentHashMap元素個數(size) > sizeCtl(0.75 * tab.length)
    1. 每次resize(rehash)我完畢之後會一直檢查是否需要再次resize(rehash)
    2. 源碼判斷邏輯:s >= (long)(sc = sizeCtl) (其中s=ConcurrentHashMap.size()
    3. 源碼判斷邏輯:sizeCtl = (n << 1) - (n >>> 1); (其中n=resize前的size)。
      1. 0.75: 2n - 0.5n = 1.5n
      2. resize後的大小2n
      3. 1.5n / 2n = 0.75

2. 怎麼resize

這塊沒看透。看透再補充
.
ConcurrentHashMap 始終維護一個 Node[] table表示當前的數據, 以及一個 Node[] newTab表示將要resize去的表。

  1. 多線程resize(rehash)
    1. 每個線程負責16個Node, 最多允許 數組有大小Capacity / 16個線程。
    2. 正在執行put的那個線程,也可能參與resize(rehash)
    3. 參與resize(rehash), 僅在當前key對應的Node結點已經被轉移,否則加鎖繼續put。
  2. resize是把舊Node轉移到一個新的Node數組(源碼2410行);
    1. resieze結束的標記(邏輯非常複雜,沒懂,參閱 JDK1.8–深度分析CONCURRENTHASHMAP原理分析sizeCtl擴容退出機制章節), 或者直接看源碼2414行。
    2. 每一個被轉移完畢的Node結點的hash = -1(ForwardingNode);
  3. rehash的方式和 HashMap 的實現方式一致
    1. 如果是鏈表, 把鏈表的每個結點rehash到新的table中。
    2. 如果是紅黑樹, 也是一樣的執行邏輯。

關於加鎖退出機制, 以及Node結點長度大於8時, 以及創建table時, 邏輯相似。 都是resize(rehash)的過程。

HashMap resize/rehash

這個相對來說, 單線程, 就比較好理解了、當size > table.length * 0.75resize/rehash 執行。

  1. resize 直接將 舊 table 賦值爲一個 2倍大小的新table
    1. 因此resize的時候可能導致get得到null(實際有值)。(多線程環境)
    2. 源碼:Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];&&table = newTab;
  2. 迭代每個數組元素Node, 對鏈表和紅黑樹遷移。
  3. 單節點直接遷移(next = null)
    1. 數組位置算法: (table.length - 1) & hash
    2. table.length 爲2^n, 則(table.length - 1)全都是二進制的1
    3. 擴容前後的值都是hash的值, 之前爲null, 之後也還是爲null. 可以直接賦值。
  4. 鏈表和紅黑樹分別rehash到新的table上去。

Redis resize/rehash

據說是 漸進式 rehash,https://www.cnblogs.com/meituantech/p/9376472.html 看不懂。

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