ConcurrentHashMap

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。http://www.cnblogs.com/jokermo/

高併發下的HashMap

1.ReHash

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

 ConcurrentHashMap能夠說是一個二級哈希表。在一個總的哈希表中,有若干個子哈希表。子哈希表能夠稱爲segment,ConcurrentHashMap結構以下:

此時的 ConcurrentHashMap採用了鎖分段技術,每一個segment的讀寫操做高度自治,segment之間互不影響。

 ConcurrentHashMap高併發讀寫操做有三種狀況:

  • 同一segment併發寫入
  • 不一樣segment的併發寫入
  • 同一segment一讀一寫

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.釋放鎖。

size方法

ConcurrentHashMap的Size方法是一個嵌套循環,大致邏輯以下:

1.遍歷全部的Segment。

2.把Segment的元素數量累加起來。

3.把Segment的修改次數累加起來。

4.判斷全部Segment的總修改次數是否大於上一次的總修改次數。若是大於,說明統計過程當中有修改,從新統計,嘗試次數+1;若是不是。說明沒有修改,統計結束。

5.若是嘗試次數超過閾值,則對每個Segment加鎖,再從新統計。

6.再次判斷全部Segment的總修改次數是否大於上一次的總修改次數。因爲已經加鎖,次數必定和上次相等。

7.釋放鎖,統計結束。

相關文章
相關標籤/搜索