1 ConcurrentHashMap的基本架构和关键方法
基本架构与HashMap一致,留出来的api也是,屏蔽了内部实现的复杂细节,主要的get,put方法是首先要看的,然后深入了是对应HashMap的扩容机制的tranfer方法,这个参见ConcurrentHashMap之transfer方法源码,桶槽等基本概念不再赘述,HashMap的扩容机制详解见HashMap扩容机制源码
2 操作的API get和put方法的同步机制
get方法作为读操作,Doug Lee大神在设计时并未给get方法加锁,基本逻辑与HashMap没有区别。
put方法作为写操作,是肯定需要同步操作的,而这里put操作加锁方式从JDK1.7的分段锁,到1.8的CAS+synchronized,是有较大变化的,我们以1.8为例来分析put操作的加锁原理。结论是:如果找到的对应位置的桶为空,则尝试CAS插入,否则用synchronized锁住头节点完成插入。具体细节见代码及注释
final V putVal(K key, V value, boolean onlyIfAbsent) {
//不同于HashMap,CHM不准加入null作为key
if (key == null || value == null) throw new NullPointerException();
//计算对应hash值
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();
//如果桶位置为空,则利用CAS操作更新
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//这个CAS也是由Unsafe这个类提供的
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