ConcurrentHashMap原始碼閱讀(一)
阿新 • • 發佈:2018-12-20
原始碼所屬版本為jdk1.8
ConcurrentHashMap:
public V put(K key, V value) {
return putVal(key, value, false);
}
這是put方法可以看到呼叫的是putVal方法。
final V putVal(K key, V value, boolean onlyIfAbsent) { //key值和value值都不能為空 if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode());//讓高位的hash值參與運算以降低碰撞概率 int binCount = 0; for (Node<K,V>[] tab = table;;) {//死迴圈 Node<K,V> f; int n, i, fh; if (tab == null || (n = tab.length) == 0)//判斷是否初始化 tab = initTable();//初始化 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//判斷表裡第i個節點是否為空 if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))//通過CAS直接新增到第i個節點中 break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED)//判斷是否是擴容節點 tab = helpTransfer(tab, f);//幫助擴容 else {//該節點已經有值 V oldVal = null; synchronized (f) {//對錶裡的第i個的頭節點加鎖 if (tabAt(tab, i) == f) {//判斷是否是頭節點 if (fh >= 0) {//判斷頭節點的hash值是否大於等於0 binCount = 1;//連結串列裡節點的數量 for (Node<K,V> e = f;; ++binCount) {//死迴圈 K ek; if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {//判斷現在的key值與連結串列裡的key值相等 oldVal = e.val; if (!onlyIfAbsent) e.val = value;//直接覆蓋 break; } Node<K,V> pred = e; if ((e = e.next) == null) {//如果下個節點為空,直接賦值。 pred.next = new Node<K,V>(hash, key, value, null); break; } } } else if (f instanceof TreeBin) {//樹節點 Node<K,V> p; binCount = 2; if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {//插入到紅黑樹中如果有返回值則改key值已存在覆蓋value值 oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } if (binCount != 0) {//連結串列節點數量不等於0 if (binCount >= TREEIFY_THRESHOLD)//判斷是否大於等於8 treeifyBin(tab, i);//轉換成紅黑樹 if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); // 統計節點個數,檢查是否需要resize return null; }