hashmap底層資料結構是hash表 ,是由陣列加鍊表加紅黑樹實現的hash表,jdk1.8之前沒有紅黑樹。
hashmap在put資料時需要先使用hash演算法結合陣列長度進行定址,找到陣列上的乙個槽位,如果槽位是空的就加入這個槽位中,如果槽位不是空的則加入該槽位上的鍊錶尾部((jdk 1.7 之前使用頭插法、jdk 1.8 使用尾插法)),若該鍊錶長度超過8則轉化為紅黑樹以提高查詢效率。
hashmap在第一次put操作時初始化底層資料結構也就是hash表。hash表也就是乙個陣列中裝entry可以作為鍊錶中的乙個節點其中包含成員變數next。陣列中的每個元素都是鍊錶,由 node 內部類(實現 map.entry介面)實現。
擴容過程:建立乙個新的陣列,其容量為舊陣列的兩倍,並重新計算舊陣列中結點的儲存位置。結點在新陣列中的位置只有兩種,原下標位置或原下標+舊陣列的大小。
concruenthashmap中的底層資料結構定義為table,inittable為初始化方法,concruenthashmap中定義了乙個volatile修飾的成員變數sizectl 用於表示是否有執行緒在進行初始化工作。
進行初始化操作時cas修改sizectl 的值之後再進行初始化
private final node inittable()
} finally
break;
}} return tab;
}
put操作
1.先檢查table是否為空,為空則初始化
2.通過u.getobjectvolatile拿出node,若為空直接cas插入資料
3.鎖住node頭
hashmap預設的初始容量是16 設定容量盡量設定2的整數次冪以減少hash衝突。
當hashmap中的元素個數超過陣列大小*loadfactor時,就會進行陣列擴容,loadfactor的預設值為0.75
hashmap陣列擴容之後,最消耗效能的點就出現了:原陣列中的資料必須重新計算其在新陣列中的位置,並放進去,這就是resize。
紅黑樹和二叉查詢樹:
之所以選擇紅黑樹是為了解決二叉查詢樹的缺陷,二叉查詢樹在特殊情況下會變成一條線性結構(這就跟原來使用鍊錶結構一樣了,造成很深的問題),遍歷查詢會非常慢。推薦:面試問紅黑樹,我臉都綠了。
而紅黑樹在插入新資料後可能需要通過左旋,右旋、變色這些操作來保持平衡,引入紅黑樹就是為了查詢資料快,解決鍊錶查詢深度的問題,我們知道紅黑樹屬於平衡二叉樹,但是為了保持「平衡」是需要付出代價的,但是該代價所損耗的資源要比遍歷線性鍊錶要少,所以當長度大於8的時候,會使用紅黑樹,如果鍊錶長度很短的話,根本不需要引入紅黑樹,引入反而會慢。
jdk 1.7 中使用分段鎖(reentrantlock + segment + hashentry),相當於把乙個 hashmap 分成多個段,每段分配一把鎖,這樣支援多執行緒訪問。鎖粒度:基於 segment,包含多個 hashentry。jdk 1.8 中使用 cas + synchronized + node + 紅黑樹。鎖粒度:node(首結點)(實現 map.entry)。鎖粒度降低了。
HashMap知識,ArrayList知識
hashtable 的擴容機制 void resize int newcapacity entry newtable new entry newcapacity transfer newtable table newtable threshold int newcapacity loadfactor...
HashMap集合的整理
1.初始容量 16 static final int default initial capacity 1 4 aka 162.最大容量2 30 static final int maximum capacity 1 30 3.載入因子 0.75 static final float default...
hashmap知識 待續
hashmap原理 hashmap是否初始化 1.hashmap預設bucket陣列多大 16 2.new hashmap 19 的時候bucket陣列多大 32 最接近19的2的冪次方 3.hashmap什麼時候開闢bucket陣列占用記憶體 put的時候 4.hashmap時擴容 put的元素達...