JDK7中HashMap鍊錶成環的原因和解決方案

2021-10-06 07:42:05 字數 1207 閱讀 9898

jdk1.7 hashmap擴容轉移鍊錶時形成環狀鍊錶的原因

大概就是:有a-

>b-

>null鍊錶

有兩個執行緒,a和b

a處理到a-

>null的時候,next指向b,接著b開始處理,並已經處理完畢,即b-

>a-

>null

然後a又繼續執行,而next指向b,所以變為b-

>a-

>null

然後a的下一次迴圈的時候因為b的b-

>a-

>null,所以next = b.next,也就是a,所以a又指向b

最後就變成a-

>b,而又b-

>a這樣的迴圈

jdk8 中解決方案(從這裡檢視的)

jdk 8 中擴容時,已經沒有 jdk7 中的 transfer 方法了,而是自己重新寫了擴容方法,叫做 resize,鍊錶從老陣列拷貝到新陣列時的**如下:

//規避了8版本以下的成環問題

else

// (e.hash & oldcap) == 0 表示新值鍊錶

else

}while

((e = next)

!= null)

;// 老值鍊錶賦值給原來的陣列索引位置

if(lotail != null)

// 新值鍊錶賦值到新的陣列索引位置

if(hitail != null)

}

解決辦法其實**中的注釋已經說的很清楚了,我們總結一下:

jdk8 是等鍊錶整個 while 迴圈結束後,才給陣列賦值,此時使用區域性變數 lohead 和 hihead 來儲存鍊錶的值,因為是區域性變數,所以多執行緒的情況下,肯定是沒有問題的。

為什麼有 lohead 和 hihead 兩個新老值來儲存鍊錶呢,主要是因為擴容後,鍊錶中的元素的索引位置是可能發生變化的,**注釋中舉了乙個例子:

陣列大小是 8 ,在陣列索引位置是 1 的地方掛著乙個鍊錶,鍊錶有兩個值,兩個值的 hashcode 分別是是 9 和 33。當陣列發生擴容時,新陣列的大小是 16,此時 hashcode 是 33 的值計算出來的陣列索引位置仍然是 1,我們稱為老值(lohead),而 hashcode 是 9 的值計算出來的陣列索引位置卻是 9,不是 1 了,索引位置就發生了變化,我們稱為新值(hihead)。

大家可以仔細看一下這幾行**,非常巧妙。

JDK7中HashMap的解析(未完)

1 hashmap採用的是資料 鍊錶的儲存結構 2 初始化預設長度為16,每次擴容 2,負載因子預設0.75 3 擴容核心類 void transfer entry newtable,boolean rehash int i indexfor e.hash,newcapacity e.next ne...

JDK7與JDK8中HashMap的實現的區別

hashmap底層維護乙個陣列,陣列中的每一項都是乙個entry transient entry table 我們向 hashmap 中所放置的物件實際上是儲存在該陣列當中 而map中的key,value則以entry的形式存放在陣列中 static class entryimplements ma...

JDK7 與 JDK8 中 HashMap 的實現

jdk7中的hashmap hashmap底層維護乙個陣列,陣列中的每一項都是乙個entry transient entry table 我們向 hashmap 中所放置的物件實際上是儲存在該陣列當中 而map中的key,value則以entry的形式存放在陣列中 static class entr...