HashMap
HashMap的數據結構
是由數組加鏈表的方式組成,有快速查找修改和方便增加刪除的優勢。結構圖如下所示
HashMap的存放過程
通過hash算法得到hashCode,根據hashCode來確定數組的索引,存到鏈表中。存入會有三個可能:
1.索引位置為空,直接放入。
2.索引位置不為空,鏈表中有相同的key值,找到替換value即可。
3.索引位置不為空,鏈表中沒有相同的key值,則將該實例插到鏈表頭部。Java8中當長度超過8時,會變成紅黑樹的方式存儲。
HashMap的查找過程
首先根據hashCode找到數組索引,然后在鏈表中根據key找到value值。整個查找過程的時間復雜度取決于存放過程是否均勻分布在每個數組中也就是hash算法。理論上時間復雜度為o(1)。
HashMap的擴容
默認的HashMap的長度是16,負載因子為0.75。當HashMap中的數量大于閾值(長度*負載因子),HashMap會進行擴容,長度變為原來的兩倍。通過rehash,得到新的hashcode將元素從舊表移動到新表中。擴容轉移過程中:
1.發生hash沖突時,Java7會在鏈表頭部插入,Java8會在鏈表尾部插入
2.擴容后轉移數據,Java7轉移前后鏈表順序會倒置,Java8還是保持原來的順序
3.關于性能對比,引入紅黑樹的Java8大程度得優化了HashMap的性能
HashMap線程不安全
HashMap是線程不安全的,容易造成死循環(Java7)和數據不一致的問題。
ConcurrentHashMap
ConcurrentHashMap結構
總結一下:帶鎖的HashMap數組,具體的hashEntry可以形成鏈表。
Segment數組S[]長度 =2的n次方(2的n次方 >= concurrencyLevel),默認concurrencyLevel = 16,根據公式Segment長度為16。concurrentcyLevel可以根據構造函數ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel)來賦值。默認S[0]中table長度為2。
ConcurrentHashMap是線程安全
有人會問HashTable也是線程安全的,兩者有什么區別:
- HashTable是對put這個操作加鎖,這會存在一個問題,就是當一個線程put操作特別長就會出現等待問題,沒有效率。
-
ConcurrentHashMap只是鎖住segments數組的某個位置,而不是整個,當另一個線程不是進入該位置時,就可以同時操作。
ConcurrentHashMap上鎖示意圖.png
什么是HashMap?
高并發下的HashMap
什么是ConcurrentHashMap
淺談HashMap與線程安全 (JDK1.8)