ConcurrentHashMap

      ConcurrentHashMap是線程安全且高效的HashMap。HaspMap可能在併發執行put的致使死循環發生,resize致使造成環。 HashTable線程安全,可是效率低下。算法

       ConsurrentHashMap經過分段鎖能夠提高效率。假如容器裏有多把鎖,每一把鎖用於鎖容器中的一部分數據。將數據分紅一段一段地存儲,而後給每一段數據配一把鎖。當一個線程佔用鎖訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問。數組

      ConconrrentHashMap是有segment數組結構和HashEntry數組結構組成。Segment是一種可重入鎖(ReentrantLock),在ConcurrentHashMap裏扮演鎖的角色,HashEntry則用於存儲鍵值對數據。Segement裏包含一個HashEntry數組,每一個HashEntry是一個鏈表結構的元素,每一個Segment守護着一個HashEntry數組裏的元素,當對HashEntry數組的數據進行修改時,首先要得到與他對應的Segment鎖。安全

      segments數組的長度ssize,爲了能經過按位與的散列算法來定位segments數組的索引,必須保證segments數組的長度是2的N次方。併發

      定位segment。既然ConcurrentHashMap使用分段鎖Segement來保護,那麼插入和獲取元素的時候,必須先經過散列算法定位到segment。會首先使用Wang/Jenkins hash的變種算法對元素的hashCode進行一次再散列。線程

      之因此進行再散列,目的是減小散列衝突,使元素可以均勻的分佈在不一樣的segement上。code

ConcurrentHashMap的操做索引

1.get操做rem

      Segment的get操做實現很是簡單和高效。先通過一次再散列,而後使用這個散列值經過散列運算定位到Segement,在經過散列算法定位到元素。get

     定位HashEntry和定位Segment的散列算法雖然同樣,都與數組的長度減去1在相「與」,可是相於的值不同,定位Segment使用的是元素的hashcode經過再散列後獲得的值的高位,而定位HashEntry直接使用的再散列後的值。目的是避免兩次散列後的值同樣,雖然元素在Segment裏散列了,可是確沒有在HashEntry裏散列開。hash

hash >>> segmentShift) & segementMask //定位Segment所使用的hash算法

int index=hash & (tab.len-1) //定位HashEntry所使用的hash算法

2.put操做

       因爲put方法裏須要對共享變量進行寫操做,必須加鎖。put先定義到Segment裏進行插入操做。插入操做須要經歷兩個步驟,第一步判斷是否須要對Segment裏的Entry數組進行擴容,第二步定位添加元素的位置,而後將其放在HashEntry數組裏。

3.size操做

      若是要統計整個ConcurrentHashMap裏元素的大小,就必須統計全部Segment裏元素的大小求和。Segment裏的全局變量count是一個volatile變量。雖然相加時能夠獲取每一個Segment的count的最新值,可是可能累計先後的count發生了變化,那麼統計結果就不許了。

      由於在累加count操做中,以前累加過的count發送變化的概率很是小,ConcurrentHashMapd的作法是先嚐試2次經過不鎖住Segement的方式來統計各個Segment大小,若是統計的過程當中發生了變化,則在採用加鎖的方式來統計全部Segment的大小。

      可經過modCount變量,在put,remove和clean方法裏操做元素將會將變量modCount進行加1,那麼在統計size先後比較modCount是否發生變化,從而得知容器的大小是否發生變化。

相關文章
相關標籤/搜索