JDK1.7
JDK1.8
//CHM initializes (an array of 16 nodes) private final node <K,V>[] initTable() {node <K,V>[] TAB; int sc; while ((tab = table) == null || tab.length == 0) { if ((sc = sizeCtl) < 0) Thread.yield(); Thread.yield(); thread.yield (); thread.yield (); Else if (U.compareAndSwapInt(this, SIZECTL, sc, - 1)) {/ / SIZECTL set to 1 try {if ((TAB = table) = = null | | TAB. The length = = 0) {/ / (TAB = table) to local variables, global variables, assignment Int n = (sc > 0)? Sc: DEFAULT_CAPACITY; //DEFAULT_CAPACITY=16 @SuppressWarnings("unchecked") Node<K,V>[] nt = (Node<K,V>[])new Node<? ,? >[n]; table = tab = nt; sc = n - (n >>> 2); // None: 16*0.75}} finally {sizeCtl = sc; } break; } } return tab; }Copy the code
Put method
// If (" Max "," architect "); final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode()); 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) {// 2,(n-1) & hash) If (casTabAt(TAB, I, null, new Node<K,V>(hash, key, value, null))) Replace Node< k,v> with a new Node<"xiaofeng"," architect "> Be careful not to treat Node< k, V > as a hashmap, it is just an underlying data Node break in hashMap; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal = null; Synchronized (f) {synchronized (f) {synchronized (f) {synchronized (f) {synchronized (f) {synchronized (f) {synchronized (f) { If (tabAt(TAB, I) == f) {if (fh >= 0) {// if (fh >= 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)))) {// if is the same key, need to overwrite value. if (! onlyIfAbsent) e.val = value; break; } Node<K,V> pred = e; // next = new Node<K,V>(hash, key, value, null); // next = new Node<K,V>(hash, key, value); break; } } } else if (f instanceof TreeBin) { Node<K,V> p; binCount = 2; if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) ! = null) { oldVal = p.val; if (! onlyIfAbsent) p.val = value; } } } } if (binCount ! = 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal ! = null) return oldVal; break; } } } addCount(1L, binCount); return null; }Copy the code
AddCount two phases: 1, initialization phase 2, concurrent update phase
private transient volatile long baseCount; Private TRANSIENT volatile CounterCell[] counterCells; private transient volatile CounterCell[] counterCells; @sun.misc.Contended static final class CounterCell {volatile long value; CounterCell(long x) { value = x; } } final long sumCount() { CounterCell[] as = counterCells; CounterCell a; long sum = baseCount; if (as ! = null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) ! = null) sum += a.value; } } return sum; } size() : public int size() {long n = sumCount(); return ((n < 0L) ? 0 : (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)n); } baseCount + (traverses the value of each CounterCell) = sum 1). CousnterCell[] value=v+x() -> CousnterCell[] FullAndCount (); private final void addCount(long x, int check) { CounterCell[] as; long b, s; //CounterCell[] as defines local variables to improve access performance if ((as = counterCells)! = null || ! U.compareAndSwapLong(this, BASECOUNT, b= BASECOUNT, s =b+x)) { long v; int m; boolean uncontended = true; / / ThreadLocalRandom. GetProbe () & m, m (array length) on random function and gets an array subscript. // if (as == null || (m = as.length - 1) < 0 || (a = as[ThreadLocalRandom.getProbe() & m]) == null || ! (uncontended = U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) { Value =v+x() fullAddCount(x, uncontended); FullAndCount (); return; } if (check <= 1) return; s = sumCount(); } if (check >= 0) { Node<K,V>[] tab, nt; int n, sc; while (s >= (long)(sc = sizeCtl) && (tab = table) ! = null && (n = tab.length) < MAXIMUM_CAPACITY) { int rs = resizeStamp(n); if (sc < 0) { if ((sc >>> RESIZE_STAMP_SHIFT) ! = rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || (nt = nextTable) == null || transferIndex <= 0) break; if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) transfer(tab, nt); } else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) transfer(tab, null); s = sumCount(); }} // Copy fullAndCount for (;;) { CounterCell[] as; CounterCell a; int n; long v; If ((as = counterCells)! = null && (n = as.length) > 0) { if ((a = as[(n - 1) & h]) == null) { if (cellsBusy == 0) { CounterCell r = new CounterCell(x); if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { boolean created = false; try { // Recheck under lock CounterCell[] rs; int m, j; if ((rs = counterCells) ! = null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { cellsBusy = 0; } if (created) break; continue; // Slot is now non-empty } } collide = false; } else if (! wasUncontended) // CAS already known to fail wasUncontended = true; Continue after rehash else if (U.compareAndSwapLong(a, CELLVALUE, v= a.value, v+x)) v=v+x break; else if (counterCells ! = as || n >= NCPU) collide = false; // At max size or stale else if (! collide) collide = true; else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, If (counterCells == as) {// Expand table unless stale CounterCell[] rs = new CounterCell[n << 1]; For (int I = 0; i < n; ++i) rs[i] = as[i]; counterCells = rs; } } finally { cellsBusy = 0; } collide = false; continue; // Retry with expanded table } h = ThreadLocalRandom.advanceProbe(h); } // counterCells is null, cellsBusy=0 means that there is no thread to operate, Else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, cellsBusy, 0, 1)) {// Enter the following logic to indicate that the current thread is qualified to initialize Boolean init = false; try { // Initialize table if (counterCells == as) { CounterCell[] rs = new CounterCell[2]; Rs [h & 1] = new CounterCell(x); //h & 1 hash value with 1 or compute subscript counterCells = rs; init = true; } } finally { cellsBusy = 0; } if (init) break; } else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) // break; // Fall back on using base }Copy the code
(addCount chart)
capacity
(When the number of elements is greater than the threshold) If the capacity is being expanded, the threads in the capacity expansion phase will assist in the capacity expansion
If (check >= 0) {Node<K,V>[] TAB, nt; int n, sc; while (s >= (long)(sc = sizeCtl) && (tab = table) ! = null && (n = tab.length) < MAXIMUM_CAPACITY) { If (sc < 0) {if ((sc >>>) RESIZE_STAMP_SHIFT)! = = = rs | | sc rs + 1 | | sc = = rs + MAX_RESIZERS | | (nt = nextTable) = = null | | transferIndex < = 0) / / if (true) does not need expansion break; if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) transfer(tab, nt); Rs << RESIZE_STAMP_SHIFT) + 2: + 2 else if (U.compareAndSwapInt(this, SIZECTL, SC, (rs << RESIZE_STAMP_SHIFT) + 2)) Transfer (TAB, null); s = sumCount(); } } static final int resizeStamp(int n) { return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1)); }Copy the code