## 1 ConcurrentHashMap 1.7
ConcurrentHashMap æ¯ Java1.5 ä¸å¼ç¨çä¸ä¸ª**线ç¨å®å
¨çæ¯æé«å¹¶å**ç HashMap éåç±»ã

å¦å¾æç¤ºï¼ç± Segment æ°ç»ãHashEntry ç»æï¼Segment çä¸ªæ°æ¯ **16** ä¸ªï¼æºç å¦ä¸æç¤ºï¼
```java
//Segment æ°ç»ï¼åæ¾æ°æ®æ¶é¦å
éè¦å®ä½å°å
·ä½ç Segment ä¸ã
final Segment[] segments;
transient Set keySet;
transient Set> entrySet;
//Segment æ¯ ConcurrentHashMap çä¸ä¸ªå
é¨ç±»
static final class Segment extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
//çæ£åæ¾æ°æ®çæ¡¶
transient volatile HashEntry[] table;
transient int count;
transient int modCount;
transient int threshold;
final float loadFactor;
}
```
ConcurrentHashMap éç¨äº**åæ®µé**ææ¯ï¼ Segment ç»§æ¿äº ReentrantLockï¼æ¯å½ä¸ä¸ªçº¿ç¨å ç¨é访é®ä¸ä¸ª Segment æ¶ï¼ä¸ä¼å½±åå°å
¶ä»ç Segmentã
### 1.1 æé åæ°
```java
public ConcurrentHashMap() {
//DEFAULT_INITIAL_CAPACITY é»è®¤åå§å容é 16
//DEFAULT_LOAD_FACTOR é»è®¤è´è½½å å 0.75f
//DEFAULT_CONCURRENCY_LEVEL é»è®¤å¹¶åçº§å« 16
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
@SuppressWarnings("unchecked")
public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel) {
//æ ¡éªåæ°
if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
//æ ¡éªå¹¶å级å«å¤§å°ï¼å¤§äº 1 << 16ï¼é置为 65536
if (concurrencyLevel > MAX_SEGMENTS)
concurrencyLevel = MAX_SEGMENTS;
int sshift = 0;
int ssize = 1;
//è¿ä¸ªå¾ªç¯å¯ä»¥æ¾å° concurrencyLevel ä¹ä¸æè¿ç 2çæ¬¡æ¹å¼
while (ssize < concurrencyLevel) {
++sshift;
ssize <<= 1;
}
//segmentShift åç§»é
this.segmentShift = 32 - sshift;
this.segmentMask = ssize - 1;
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
int c = initialCapacity / ssize;
if (c * ssize < initialCapacity)
++c;
int cap = MIN_SEGMENT_TABLE_CAPACITY;
//Segment ä¸çç±»ä¼¼äº HashMap ç容éè³å°æ¯2æè
2çåæ°
while (cap < c)
cap <<= 1;
// å建 Segment æ°ç»ï¼è®¾ç½® segments[0]
Segment s0 = new Segment(loadFactor, (int)(cap * loadFactor),
(HashEntry[])new HashEntry[cap]);
Segment[] ss = (Segment[])new Segment[ssize];
UNSAFE.putOrderedObject(ss, SBASE, s0);
this.segments = ss;
}
```
### 1.2 put
```java
public V put(K key, V value) {
Segment s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment)UNSAFE.getObject
(segments, (j << SSHIFT) + SBASE)) == null)
//妿 Segment 为空ï¼ååå§åï¼å®é
éè¿ key å®ä½å° Segment
s = ensureSegment(j);
//å¨ Segment ä¸ put
return s.put(key, hash, value, false);
}
//Segment.java
inal V put(K key, int hash, V value, boolean onlyIfAbsent) {
//1.tryLock():å°è¯è·åé
HashEntry node = tryLock() ? null :
//2.scanAndLockForPut():èªæè·åé
scanAndLockForPut(key, hash, value);
V oldValue;
try {
HashEntry[] tab = table;
int index = (tab.length - 1) & hash;
// CAS è·å index åæ çå¼
HashEntry first = entryAt(tab, index);
for (HashEntry e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key ||
(e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
}
else {
if (node != null)
node.setNext(first);
else
node = new HashEntry(hash, key, value, first);
int c = count + 1;
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}
```
ä¸é¢æä¸¤ä¸ªæ¯è¾éè¦çæ¹æ³ tryLock() å canAndLockForPut()ï¼ææå°±æ¯å°è¯è·åéï¼å¦æè·å失败è¯å®å°±æå
¶ä»çº¿ç¨åå¨ç«äºï¼åå©ç¨ scanAndLockForPut() èªæè·åéã
```java
private HashEntry scanAndLockForPut(K key, int hash, V value) {
//é®å¼å¯¹çhashå¼å®ä½å°æ°ç»tabç第ä¸ä¸ªé®å¼å¯¹
HashEntry first = entryForHash(this, hash);
HashEntry e = first;
HashEntry node = null;
int retries = -1;
//线ç¨å°è¯éè¿CASè·åé
while (!tryLock()) {
HashEntry f;
if (retries < 0) {
if (e == null) {
if (node == null)
//åå§åé®å¼å¯¹ï¼nextæånull
node = new HashEntry(hash, key, value, null);
retries = 0;
}
else if (key.equals(e.key))
retries = 0;
else
e = e.next;
}
//è¶
è¿æå¤§èªææ¬¡æ°ï¼é»å¡
else if (++retries > MAX_SCAN_RETRIES) {
lock();
break;
}
//头èç¹åçååï¼éæ°éå
else if ((retries & 1) == 0 &&
(f = entryForHash(this, hash)) != first) {
e = first = f;
retries = -1;
}
}
return node;
}
```
1. éè¿ key ï¼è·åå½å Segment å¹¶å®ä½å° HashEntryã
2. éå HashEntryï¼å¦æä¸ä¸ºç©ºåå¤æä¼ å
¥ç key åå½åéåç key æ¯å¦ç¸çï¼ç¸çåè¦çæ§ç valueã
3. ä¸ä¸ºç©ºåæ°å»º HashEntry å¹¶å å
¥å° Segment ä¸ï¼åæ¶ä¼å
夿æ¯å¦éè¦æ©å®¹ã
4. æåè§£é¤ scanAndLockForPut() 䏿è·åå½å Segment çéã
### 1.3 get
```java
public V get(Object key) {
Segment s;
HashEntry[] tab;
//hash è¿ç®
int h = hash(key);
long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
if ((s = (Segment)UNSAFE.getObjectVolatile(segments, u)) != null &&
(tab = s.table) != null) {
for (HashEntry e = (HashEntry) UNSAFE.getObjectVolatile
(tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
e != null; e = e.next) {
K k;
if ((k = e.key) == key || (e.hash == h && key.equals(k)))
return e.value;
}
}
return null;
}
```
å° Key éè¿ Hash ä¹åå®ä½å°å
·ä½ç Segment ï¼åéè¿ä¸æ¬¡ Hash å®ä½å°å
·ä½çå
ç´ ä¸ã
HashEntry ä¸ç value æ¯ç¨ volatile å
³é®è¯ä¿®é¥°çï¼ä¿è¯å
åå¯è§æ§ï¼æ¯æ¬¡è·åæ¶é½æ¯ææ°å¼ã
### 1.4 rehash
```java
private void rehash(HashEntry node) {
HashEntry[] oldTable = table;
//è容é
int oldCapacity = oldTable.length;
//æ°å®¹éï¼æ©å¤§ä¸¤å
int newCapacity = oldCapacity << 1;
//æ°çæ©å®¹éå¼
threshold = (int)(newCapacity * loadFactor);
//å建æ°çæ°ç»
HashEntry[] newTable = (HashEntry[]) new HashEntry[newCapacity];
int sizeMask = newCapacity - 1;
for (int i = 0; i < oldCapacity ; i++) {
HashEntry e = oldTable[i];
if (e != null) {
HashEntry next = e.next;
//è®¡ç®æ°çä½ç½®
int idx = e.hash & sizeMask;
if (next == null)
//妿å½åä½ç½®è¿ä¸æ¯é¾è¡¨ï¼åªæ¯ä¸ä¸ªå
ç´ ï¼ç´æ¥èµå¼
newTable[idx] = e;
else { //é¾è¡¨
HashEntry lastRun = e;
int lastIdx = idx;
for (HashEntry last = next; last != null; last = last.next) {
int k = last.hash & sizeMask;
if (k != lastIdx) {
lastIdx = k;
lastRun = last;
}
}
//lastRun åé¢çå
ç´ ä½ç½®é½æ¯ç¸åçï¼ç´æ¥ä½ä¸ºé¾è¡¨èµå¼å°æ°ä½ç½®ã
newTable[lastIdx] = lastRun;
for (HashEntry p = e; p != lastRun; p = p.next) {
//éåå©ä½å
ç´ ï¼å¤´ææ³å°æå® k ä½ç½®ã
V v = p.value;
int h = p.hash;
int k = h & sizeMask;
HashEntry n = newTable[k];
newTable[k] = new HashEntry(h, p.key, v, n);
}
}
}
}
//å¤´ææ³æå
¥æ°çèç¹
int nodeIndex = node.hash & sizeMask;
node.setNext(newTable[nodeIndex]);
newTable[nodeIndex] = node;
table = newTable;
}
```
## 2 ConcurrentHashMap 1.8
1.7 å·²ç»è§£å³äºå¹¶åé®é¢ï¼å¹¶ä¸è½æ¯æ N 个 Segment è¿ä¹å¤æ¬¡æ°çå¹¶åï¼ä½æ¯æ¥è¯¢éåé¾è¡¨æç太ä½ï¼ConcurrentHashMap 1.8 æå¼ **Segment åæ®µé**ï¼èéç¨äº CAS + synchronized æ¥ä¿è¯å¹¶åå®å
¨æ§ãæ°æ®ç»æ**Segment æ°ç» + HashEntry æ°ç» + é¾è¡¨**ä¹åæ **Node æ°ç» + é¾è¡¨ / çº¢é»æ **ã

### 2.1 put
```java
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[] tab = table;;) {
Node f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
//æ°ç»æ¡¶ä¸ºç©ºï¼åå§åæ°ç»æ¡¶ï¼èªæ+CAS)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//CASæä½å¾å°å¯¹åº table ä¸å
ç´
if (casTabAt(tab, i, null,new Node(hash, key, value, null)))
break;
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//å é
synchronized (f) {
if (tabAt(tab, i) == f) {
// é¾è¡¨
if (fh >= 0) {
binCount = 1;
//循ç¯å å
¥æ°çæè
è¦çèç¹
for (Node 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 pred = e;
if ((e = e.next) == null) {
pred.next = new Node(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
//çº¢é»æ
Node p;
binCount = 2;
if ((p = ((TreeBin)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;
}
```
- æ ¹æ® key 计ç®åº hashcode ã
- 夿æ¯å¦éè¦è¿è¡åå§åã
- `f` å³ä¸ºå½å key å®ä½åºç Nodeï¼å¦æä¸ºç©ºè¡¨ç¤ºå½åä½ç½®å¯ä»¥åå
¥æ°æ®ï¼å©ç¨ CAS å°è¯åå
¥ï¼å¤±è´¥åèªæä¿è¯æåã
- 妿å½åä½ç½®ç `hashcode == MOVED == -1`,åéè¦è¿è¡æ©å®¹ã
- 妿é½ä¸æ»¡è¶³ï¼åå©ç¨ synchronized éåå
¥æ°æ®ã
- 妿æ°éå¤§äº `TREEIFY_THRESHOLD` åè¦è½¬æ¢ä¸ºçº¢é»æ ã
### 2.2 get
```java
public V get(Object key) {
Node[] tab; Node e, p; int n, eh; K ek;
//key æå¨ç hash ä½ç½®
int h = spread(key.hashCode());
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
//妿æå®ä½ç½®å
ç´ åå¨ï¼å¤´ç»ç¹hashå¼ç¸å
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
//key hash å¼ç¸çï¼keyå¼ç¸åï¼ç´æ¥è¿åå
ç´ value
return e.val;
}
else if (eh < 0)
//头ç»ç¹hashå¼å°äº0ï¼è¯´ææ£å¨æ©å®¹æè
æ¯çº¢é»æ ï¼findæ¥æ¾
return (p = e.find(h, key)) != null ? p.val : null;
while ((e = e.next) != null) {
//é¾è¡¨ï¼é忥æ¾
if (e.hash == h &&
((ek = e.key) == key || (ek != null && key.equals(ek))))
return e.val;
}
}
return null;
}
```
1. æ ¹æ® hash å¼è®¡ç®ä½ç½®ã
2. æ¥æ¾å°æå®ä½ç½®ï¼å¦æå¤´èç¹å°±æ¯è¦æ¾çï¼ç´æ¥è¿åå®ç value.
3. 妿头èç¹ hash å¼å°äº 0 ï¼è¯´ææ£å¨æ©å®¹æè
æ¯çº¢é»æ ï¼æ¥æ¾ä¹ã
4. 妿æ¯é¾è¡¨ï¼é忥æ¾ä¹ã