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...