HashTable -> ConcurrentHashMap 1.7 -> ConcurrentHashMap 1.8
这个过程本质上是优化锁的使用,包括锁粒度细化、CAS
- 锁粒度细化,方法级别互斥锁 -> 对哈希表分段后加锁 -> 对链表表头对象加锁
// HashTable
public synchronized V put(K key, V value) {...}
// ConcurrentHashMap JDK 1.7
static final class Segment<K,V> extends ReentrantLock implements Serializable {...} // 意味着 Segment 本身即为可重入锁,因此对分段对象的访问自带锁功能
// ConcurrentHashMap JDK 1.8
Node<K,V> f;
f = tabAt(tab, i = (n - 1); // 取得链表表头/红黑树引用
synchronized (f) { // 加锁
...
}
- 使用 CAS 乐观锁
// ConcurrentHashMap JDK 1.7
if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
== null) { // recheck
Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
== null) {
// 初始化设置分段数组
if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
break;
}
}
// ConcurrentHashMap JDK 1.8
// 链表为空时,设置初始节点
if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))