HashMap和ConcurrentHashMap和HashTable的底層原理與剖析
阿新 • • 發佈:2018-11-26
HashMap 可以允許key為null,value為null,但HashMap的是執行緒不安全的 HashMap 底層是陣列 + 連結串列的資料結構
- 在jdk 1.7 中 map集合中的每一項都是一個 entry
- 在jdk 1.8 中 map 集合中的每一項都是一個node
這張圖我解釋一下 在每個HashMap中 維護了四個屬性 分別是 hash ,map ,key ,next
因為底層是陣列加連結串列 陣列的預設大小是16 每一個 使用者put值的時候都會向這個陣列進行新增 這裡的新增演算法就是 hash演算法,一旦使用者的資料向這個陣列的某一項進行第二次輔助則這時就會使用連結串列的資料結構 一直向下延申 這個是jdk1.7 的做法
而到了jdk1.8以後 在延申的過程中一旦發現 延申的數量大於8個就會使用另一種的資料結構 紅黑樹以樹的形式進行擴充套件進行新增
這時肯定會有人問剛剛一直往下延申這時 的橫向延申不夠怎麼辦 就是陣列的長度不足怎麼辦 這時陣列當然也是會擴容 以原理的二倍進行擴容相對來說效率比較高
HashMap 陣列+連結串列+紅黑樹 在單執行緒的情況下簡直是完美的
但在多執行緒的情況下是不完美的 會導致執行緒不安全
執行緒不安全 :
多執行緒操作一系列操作的時候和單執行緒操作表現的結果不致就說明執行緒非安全在 hashmap1.7中頭插法hsah map 是執行緒不安全的
這時我們的Hashtable 出現了
- hashtable不接受key 或者 value為空
- 執行緒安全
但是 是執行緒安全的 但在高併發 或者負載均衡的輪詢等 效率太 低
ConcurrentHashMap
採用的是分段鎖
在併發的概念中 有一個程式設計思想是CAS方式 採用無鎖的方式 保證執行緒的安全 保證了原子性 效率比 synchronized 高
接下來我們對比一下HashMap 和 ConcurrentHashMap的put 方式
Hashmap 的put方法
ConcurrentHashMap的put 方法
點入到ConcurrentHashMap的put 方法
這時我們在ConcurrentHashMap集合中看到 好多volatile關鍵字
volatile
這個關鍵字 保證每次讀到的都是主記憶體裡面最新的值
- 擴容:段內擴容(段內元素超過該段對應Entry陣列長度的75%觸發擴容,不會對整個Map進行擴容),插入前檢測需不需要擴容,有效避免無效擴容
- ConcurrentHashMap預設將hash表分為16個桶,諸如get、put、remove等常用操作只鎖住當前需要用到的桶。這樣,原來只能一個執行緒進入,現在卻能同時有16個寫執行緒執行,併發效能的提升是顯而易見的。