rehash是HashMap擴容時的一個步驟,Hashmap的長度有限,不斷插入數據,當hashmap達到必定飽和時,hash衝突機率會提升。這時候hashmap就須要進行擴容,也就是Resize。數組
影響發生Resize的因素有兩個:安全
1.Capacity多線程
HashMap的當前長度。HashMap的長度是2的冪。併發
2.LoadFactor高併發
HashMap負載因子,默認值爲0.75f。spa
衡量HashMap是否進行Resize的條件以下:線程
HashMap.Size >= Capacity * LoadFactorcode
ReHash的Java代碼以下:對象
void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }
.Hashmap的Resize包含擴容和ReHash兩個步驟,ReHash在併發的狀況下可能會造成鏈表環。因此HashMap不能用於多線程blog
ConcurrentHashMap能夠說是一個二級哈希表。在一個總的哈希表中,有若干個子哈希表。子哈希表能夠稱爲segment,ConcurrentHashMap結構以下:
此時的 ConcurrentHashMap採用了鎖分段技術,每一個segment的讀寫操做高度自治,segment之間互不影響。
ConcurrentHashMap高併發讀寫操做有三種狀況:
Segment的寫入是須要上鎖的,所以對同一Segment的併發寫入會被阻塞。
因而可知,ConcurrentHashMap當中每一個Segment各自持有一把鎖。在保證線程安全的同時下降了鎖的粒度,讓併發操做效率更高。
ConcurrentHashMap的讀寫過程:
Get方法:
1.爲輸入的Key作Hash運算,獲得hash值。
2.經過hash值,定位到對應的Segment對象
3.再次經過hash值,定位到Segment當中數組的具體位置。
Put方法:
1.爲輸入的Key作Hash運算,獲得hash值。
2.經過hash值,定位到對應的Segment對象
3.獲取可重入鎖
4.再次經過hash值,定位到Segment當中數組的具體位置。
5.插入或覆蓋HashEntry對象。
6.釋放鎖。
ConcurrentHashMap的Size方法是一個嵌套循環,大致邏輯以下:
1.遍歷全部的Segment。
2.把Segment的元素數量累加起來。
3.把Segment的修改次數累加起來。
4.判斷全部Segment的總修改次數是否大於上一次的總修改次數。若是大於,說明統計過程當中有修改,從新統計,嘗試次數+1;若是不是。說明沒有修改,統計結束。
5.若是嘗試次數超過閾值,則對每個Segment加鎖,再從新統計。
6.再次判斷全部Segment的總修改次數是否大於上一次的總修改次數。因爲已經加鎖,次數必定和上次相等。
7.釋放鎖,統計結束。