ConcurrentHashMap1.8原始碼學習之擴容(連結串列結構)

Benjamin Jane發表於2020-10-06

讀原始碼時,transfer(Node<K,V>[] tab, Node<K,V>[] nextTab)方法總是看不懂,咋整呢?畫圖吧,梳理下執行過程。初始容量16,標號為0的槽位下各節點Hash值如下圖,

int n = tab.length

int runBit = fh & n;

Node<K,V> lastRun = f;

如圖n=16,二進位制位10000,如果fh是10000,那麼runBit=10000&10000(16&16)=10000

第一次執行100000節點;b=0,runBit=10000,b!=runBit為true,runBit=0,lastRun=100000節點。

第二次執行110000節點,b=10000(16),runBit=0,b!=runBit為true。runBit=10000(16),lastRun=110000節點。

第三次執行1100000節點,b=0,runBit=10000(16),b!=runBit為true,runBit=0,lastRun=1100000節點。

第四次執行1110000節點,b=10000(16),runBit=0,b!=runBit為true,runBit=10000(16),lastRun=1110000節點。

結束。

//得到最後一個和前面的節點 高位 不一樣的節點和高位(0或10000)

 for (Node<K,V> p = f.next; p != null; p = p.next) {

      int b = p.hash & n;

      if (b != runBit) {

      runBit = b;

      lastRun = p;

       }

}

 

//如果最後一個高位不一樣的節點高位是0,則設定低位節點

if (runBit == 0) {

   ln = lastRun;

   hn = null;

 }

//如果最後一個高位不一樣的節點高位是1,則設定高位節點

 else {

     hn = lastRun;

    ln = null;

}

//具體到該例子,hn=1110000,ln=null

//這裡從該槽位的根節點開始

//第一次執行10000&10000(16&16)=10000,走else分支,ln=null,

hn=new Node<K,V>(10000, Node10000.key, Node10000.val, Node1110000);新節點如圖:

//第二次執行100000&10000(32&16)=0,走if分支,

ln=new Node<K,V>(100000, node10000.key,  ndoe100000.val,   null),新節點如圖:

1100000(96)節點執行後由於最後一個節點和lastRun是同一個節點,故1110000(112)節點不參與執行。

最終hn節點如圖:

Ln節點如圖:

for (Node<K,V> p = f; p != lastRun; p = p.next) {

      int ph = p.hash; K pk = p.key; V pv = p.val;

      if ((ph & n) == 0)

           ln = new Node<K,V>(ph, pk, pv, ln);

      else

           hn = new Node<K,V>(ph, pk, pv, hn);

 }

//低位節點仍然掛在了新陣列同樣的下標位置,

setTabAt(nextTab, i, ln);

//高位節點掛在了新陣列i+n的位置

setTabAt(nextTab, i + n, hn);

//節點處理完畢

setTabAt(tab, i, fwd);

advance = true;

擴容後節點如圖:

 

 

相關文章