ConcurrentHashMap
在 JDK1.7 的 實 現 上 , ConrruentHashMap 由一個個 Segment 組 成 , 簡 單 來 說 ,ConcurrentHashMap 是一個 Segment 數組,它經過繼承 ReentrantLock 來進行加鎖,經過每次鎖住一個 segment 來保證每一個 segment 內的操做的線程安全
當每一個操做分佈在不一樣的 segment 上的時候,默認狀況下,理論上能夠同時支持 16 個線程的併發寫入 JDK1.8算法
- 取消了 segment 分段設計,直接使用 Node 數組來保存數據,而且採用 Node 數組元素做爲鎖來實現每一行數據進行加鎖來進一步減小併發衝突的機率
- 將本來數組+單向鏈表的數據結構變動爲了數組+單向鏈表+紅黑樹的結構。
爲何要引入紅黑樹呢?
在正常狀況下,key hash 以後若是可以很均勻的分散在數組中,那麼 table 數組中的每一個隊列的長度主要爲 0 或者 1.可是實際狀況下,仍是會存在一些隊列長度過長的狀況。若是還採用單向列表方式,那麼查詢某個節點的時間複雜度就變爲 O(n); 所以對於隊列長度超過 8 的列表,JDK1.8 採用了紅黑樹的結構,那麼查詢的時間複雜度就會下降到O(logN),能夠提高查找的性能;
線程 A 的putVal 中的casTabAt 操做,具備 volatile 讀寫相同的內存語義,根據 volatile 的 happens-before 規則:線程 A 的 casTabAt 操做,必定對線程 B 的 tabAt 操做可見
initTable
sizeCtl -1表示一個佔位符,若是sizeCtl=-1,表示當前已經有線程搶到了初始化的權限 大於0的數字 sizeCtl = sc = n*0.75=12 表示下一次擴容的大小數組
addCount 計數
CounterCell 保證併發計數
ConcurrentHashMap 是採用 CounterCell 數組分片的方法來記錄元素的個數
CounterCell 數組的每一個元素,都存儲一個元素個數,而實際咱們調用size 方法就是經過這個循環累加來獲得的
CounterCells 初始化長度爲 2 的數組,而後隨機獲得指定的一個數組下標,將須要新增的值加入到對應下標位置處安全
併發擴容數據遷移
ConcurrentHashMap 支持併發擴容,實現方式是,把 Node 數組進行拆分,讓每一個線程處理本身的區域,假設 table 數組總長度是 64,默認狀況下,那麼每一個線程能夠分到 16 個 bucket。而後每一個線程處理的範圍,按照倒序來作遷移。
ConcurrentHashMap 在作鏈表遷移時,會用高低位來實現 ConcurrentHashMap 的根據下標獲取對象的算法來看,在 putVal 方法中(f = tabAt(tab, i = (n - 1) & hash)) == null經過(n-1) & hash 來得到在 table 中的數組下標來獲取節點數據。
假設咱們的 table 長度是 16, 二進制是【0001 0000】,減一之後的二進制是 【0000 1111】 假如某個 key 的 hash 值=9,對應的二進制是【0000 1001】,那麼按照(n-1) & hash 的算法0000 1111 & 0000 1001 =0000 1001 , 運算結果是 9 當咱們擴容之後,16 變成了 32,那麼(n-1)的二進制是 【0001 1111】仍然以 hash 值=9 的二進制計算爲例0001 1111 & 0000 1001 =0000 1001 ,運算結果仍然是 9 咱們換一個數字,假如某個 key 的 hash 值是 20,對應的二進制是【0001 0100】,仍然按照(n-1) & hash算法,分別在 16 爲長度和 32 位長度下的計算結果 16 位: 0000 1111 & 0001 0100=0000 0100 32 位: 0001 1111 & 0001 0100 =0001 0100 從結果來看,一樣一個 hash 值,在擴容前和擴容以後,獲得的下標位置是不同的,這種狀況固然是不容許出現的,因此在擴容的時候就須要考慮,而使用高低位的遷移方式,就是解決這個問題. 能夠看到,16 位的結果到 32 位的結果,正好增長了 16. 好比 20 & 15=4 、20 & 31=20 ; 4-20 =16 好比 60 & 15=12 、60 & 31=28; 12-28=16 因此對於高位,直接增長擴容的長度,當下次 hash 獲取數組位置的時候,能夠直接定位到對應的位置。這個地方又是一個很巧妙的設計,直接經過高低位分類之後,就使得不須要在每次擴容的時候來從新計算 hash,極大提高了效率。
鏈表長度大於 8,那麼就會觸發擴容或者紅黑樹的轉化操做。數據結構