HashMap底層原理

2021-10-09 13:29:58 字數 1527 閱讀 3192

hashmap實現map介面,非執行緒安全的,區別於concurrenthashmap。允許使用null值和null鍵,不保證對映的順序.底層資料結構是乙個「陣列+鍊錶+紅黑樹「

put():

根據key計算得到key.hash = (h = k.hashcode()) ^ (h >>> 16);

根據key.hash計算得到桶陣列的索引index = key.hash & (table.length - 1),這樣就找到該key的存放位置了:

① 如果該位置沒有資料,用該資料新生成乙個節點儲存新資料,返回null;

② 如果該位置有資料是乙個紅黑樹,那麼執行相應的插入 / 更新操作

③ 如果該位置有資料是乙個鍊錶,分兩種情況一是該鍊錶沒有這個節點,另乙個是該鍊錶上有這個節點,注意這裡判斷的依據是key.hash是否一樣: 如果該鍊錶沒有這個節點,那麼採用尾插法新增節點儲存新資料,返回null; 如果該鍊錶已經有這個節點了,那麼找到該節點並更新新資料,返回老資料。

3.更新size和閾值

擴容機制

擴容時機:

1)當鍊表長度大於8的時候並且陣列的長度小於64時優先進行擴容

2) 當元素個數大於閾值時,進行擴容。

怎麼擴容:

呼叫resize()方法方法,

1.首先進行異常情況的判斷,如是否需要初始化,二是若當前容量》最大值則不擴容,

2.然後根據新容量(是就容量的2倍、)新建陣列,將舊陣列上的資料(鍵值對)轉移到新的陣列中,這裡包括:(遍歷舊陣列的每個元素,重新計算每個資料在陣列中的存放位置。(原位置或者原位置+舊容量),將舊陣列上的每個資料逐個轉移到新陣列中,這裡採用的是尾插法。)

3.新陣列table引用到hashmap的table屬性上

4.最後重新設定擴容闕值,此時雜湊表table=擴容後(2倍)&轉移了舊資料的新table

concurrenthashmap的jdk8已經摒棄了segment段鎖的概念,由於在於jdk8的鎖粒度更細,理想情況下talbe陣列元素的大小就是其支援併發的最大個數,資料結構採用volatile修飾的table陣列+單向鍊錶+紅黑樹的結構,併發控制使用synchronized和cas來操作,整個看起來就像是優化過且執行緒安全的hashmap。

get()

計算hash值,定位到該table索引位置,如果是首節點符合就返回

如果遇到擴容的時候,會呼叫標誌正在擴容節點forwardingnode的find方法,查詢該節點,匹配就返回

以上都不符合的話,就往下遍歷節點,匹配就返回,否則最後就返回null

put(): 對當前的table進行無條件自迴圈直到put成功

如果沒有初始化就先呼叫inittable()方法來進行初始化過程

如果沒有hash衝突就直接cas插入

如果還在進行擴容操作就先進行擴容(forwardingnode的hash值判斷)

如果存在hash衝突,就加鎖來保證執行緒安全,這裡有兩種情況,一種是鍊錶形式就直接遍歷到尾端插入,一種是紅黑樹就按照紅黑樹結構插入,

最後乙個如果該鍊錶的數量大於閾值8,就要先轉換成黑紅樹的結構,break再一次進入迴圈(樹化)

HashMap底層原理

1.hashmap概述 hashmap是基於雜湊表的map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。2.hashmap的資料結構 注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的併發修改時,不可...

HashMap底層原理

預設負載因子 static final float default load factor 0.75f 無參構造 public hashmap 有參構造 public hashmap int initialcapacity public hashmap int initialcapacity,flo...

HashMap底層原理

1.8之前 hashmap在儲存元素時,首先會獲取元素的雜湊值結合位移運算,計算出該元素在陣列中的位置,如果當前位置沒有元素,就在該位置直接新增元素,如果該位置已存在其他元素,就會呼叫hashcode方法,來比較元素的hashcode值是否一致,如果不一致,那麼就在該索引位置上劃分出乙個節點來儲存當...