深入Map集合原始碼的幾個實現

2021-08-08 02:06:58 字數 3050 閱讀 8810

一、對hashmap原始碼的深入理解

1、hashmap 預設16個陣列元素大小,載入因子0.75f

2、記載因子用來計算下次擴容的臨界值(寄不是entry陣列滿了之後才進行擴容,而是到了陣列到了擴容臨界值就進行擴容)

3、hashmap 能存入空key(也能儲存null值),但是只能存乙個null,多個null的key會被後面的覆蓋,並且始終是存放在map第一位

4、hashmap entry陣列裡每個元素儲存的是乙個鍊錶的頭結點

5、hashmap 存資料的過程

1、根據hashcode計算hash值

2、根據hash值和當前entry大小計算entry陣列(hash%length)

3、處理hash相同的情況下key釋放一致:

判斷當前key的陣列裡面是否已經存在entry物件,然後判斷

if(e.hash == hash && ((k = e.key) == key || key.equals(k)))

hash和key相等,做資料的覆蓋(hashmap的key不能重複)

4、新增entry陣列

判斷當前陣列大小是否已經到了擴容臨界值並且當前陣列位置已經存在資料(儘量減少hash衝突)

if(size >= threshold) && (null != table[bucketindex])

resize(2 * table.length)擴容為當前的兩倍

建立新陣列並且把舊陣列和新陣列合併(影響效率操作)

重新計算hash值和新的陣列下標

建立entry元素

entrye = table[bucketindex] 

獲取當前要插入位置的entry元素(null或者是個鍊錶)

最終將最新插入資料放在了鍊錶的頭(before)

6、hashmap 取資料

通過hash值定位到entry陣列下標,然後通過遍歷鍊錶的方式判斷hash和key是否都相等來定位到真實的資料

二、對hashtable原始碼的深入理解(原始碼比hashmap的粗糙)

1、hashtable 預設11個陣列元素大小,載入因子0.75f

2、hashtable 最小陣列是1(小於0直接丟擲異常,等於0設定為1)

3、hashtable 不能儲存null的值,否則直接丟擲異常

4、hashtable 存資料屬於執行緒安全(put方法上使用了sychronized關鍵字)

5、hashtable 存資料的過程

1、value等於null直接丟擲空異常(key等會null也會丟擲異常,計算hashcode的時候)

2、根據hashcode計算hash值

3、根據hash值和乙個十六進製制的數與當前entry大小計算entry陣列(hash & 0x7fffffff) % tab.length

4、處理hash相同的情況下key釋放一致

(e.hash == hash) && e.key.equals(key)

如果一致直接覆蓋

5、entry陣列大小大於擴容臨界值,進行hash重組

6、建立entry元素(與hashmap一致)

三、對concurrenthashmap原始碼的深入理解(*在hashmap的基礎上使用segment做分片加鎖操作,預設16個(concurrency level),然後每次操作對乙個segment加鎖,避免多執行緒鎖的機率,提高併發效率)

1、concurrenthashmap 預設16個陣列元素大小,載入因子是0.75f,segment大小預設為16(即16個segment碎片)

2、concurrenthashmap 是在hashentry(類似於entry)的基礎上封裝了一層segment(碎片,每個碎片是個hashtable執行緒安全)

3、concurrenthashmap 使用的是鎖分離技術(segment)使用多個鎖來控制對hash表的不同部分進行修改

4、concurrenthashmap 存資料的過程

1、value和key等於null會丟擲異常

2、根據hashcode計算hash值

3、根據hash值計算所在的碎片(hash >>> segmentshift) & segmentmask

4、從碎片中出hashentry陣列,放到乙個新定義的segment中

5、往segment中的hashentry新增元素

1、trylock() ? null :  scanandlockforput(key, hash, value)  //判斷是否已經把當前segment操作鎖住

2、計算當前key在hashentry陣列的位置(tab.length - 1) & hash

3、判斷是陣列位置是否有元素(即獲取鍊錶的頭節點)

做了乙個死迴圈操作:目的是讓操作只能在頭部進行

頭節點(first)不為空:如果hash值和key相等

if ((k = e.key) == key || (e.hash == hash && key.equals(k))) 做value的替換操作

四、對hashmap和hashtable的比較

1、不設定大小的情況下預設大小不一樣(hashmap陣列長度是16、hashtable預設陣列長度是11)

2、hash支付空的key和value,hashtable不支援(hashtable存空key會直接報錯)

3、entry陣列下標位置的計算方式不一樣

hashmap:h & (length-1)

hashtable:(hash & 0x7fffffff) % tab.length

4、hashmap執行緒不安全,hashtbale執行緒安全(sychronized效率比較低,鎖住整張hash表)        

5、entry陣列擴容規則不一樣

hashmap:2*table.length

hashtable:(oldcapacity << 1) + 1 (2n+1的規則) 

6、方法的不同

hashmap:有containsvalue和containskey

hashtable:有contains方法方法

Map集合 原始碼分析

map的實現類的結構 map 雙列資料,儲存key value對的資料 hashmap 作為map的主要實現類 執行緒不安全的,效率高 可以儲存null和key的value hashmap的底層 陣列 鍊錶 jdk7之前 陣列 鍊錶 紅黑樹 jdk8 linkedhashmap 保證在遍歷map元素...

Java集合之 Map原始碼解析

hashmap 也是我們平時開發中使用頻率很高的雙列集合,直接父類是abstractmap,是基於hash表儲存的一種集合。幾個重要的類變數 hash表的初始化大小,預設為16.是基於陣列實現的。static final int default initial capacity 1 4 aka 16...

關於Map的原始碼分析

map是乙個介面,其中有一些常用的方法,j a8以後新增了很多新方法 j a8中新增的方法 其中都有這樣一句話 預設實現不會保證此方法的同步或原子屬性。提供原子性保證的任何實現都必須覆蓋此方法並記錄其併發屬性。1 返回的結果為指定鍵對映到的值,如果此對映不包含該鍵的對映,defaultvalue d...