JDK1.7, Adopt section lock technology
In essence, we still use arrays + The form of linked list stores key value pairs . To improve concurrency , The original whole table Divided into n individual Segment . On the whole , It's a product of Segment
Array of . each Segment It's made up of HashEntry Array of , each HashEntry And a linked list can be formed between them . We can take each one Segment
Think of it as a small one HashMap, Its internal structure and HashMap It's as like as two peas . When it comes to Segment When locking , It won't affect the rest of the world Segment
Reading and writing in English , Reduce lock competition .
JDK1.8, The method used is Synchronized + CAS + volatile
Synchronized Due to lock optimization and lock upgrade, the performance has been greatly improved , adopt CAS Optimistic lock realizes atomic operation , utilize volatile Ensure visibility .
Below JDK1.8ConcurrentHashMap Simple analysis of source code :
volatile Extensive use
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K
key; volatile V val; volatile Node<K,V> next; } static final class
TreeBin<K,V> extends Node<K,V> { TreeNode<K,V> root; volatile TreeNode<K,V>
first; volatile Thread waiter; volatile int lockState; } transient volatile
Node<K,V>[] table; private transient volatile Node<K,V>[] nextTable; private
transient volatile long baseCount; private transient volatile int sizeCtl;
private transient volatile int transferIndex; private transient volatile int
cellsBusy; private transient volatile CounterCell[] counterCells;
put()
public V put(K key, V value) { return putVal(key, value, false); } 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) { // adopt CAS
Atomic operation , Insert a new node into this location , This ensures that only one thread can CAS success , Other threads will fail . if (casTabAt(tab, i, null, new
Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin
} else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal
= null; // How to use synchronization lock , To ensure thread safety , Lock the head node synchronized (f) { if (tabAt(tab, i) == f) {
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)))) {
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) { oldVal = p.val; if
(!onlyIfAbsent) p.val = value; } } } } if (binCount != 0) { if (binCount >=
TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal;
break; } } } // Add to the number of elements 1, Expansion may be triggered addCount(1L, binCount); return null; }
Technology