concurrentHashMap源码解析
Posted 皓洲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了concurrentHashMap源码解析相关的知识,希望对你有一定的参考价值。
concurrentHashMap源码解析
put解析
public V put(K key, V value) {
return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
//判断key和value 不能为null
if (key == null || value == null) throw new NullPointerException();
//通过key计算hash值(高16位异或低16位)
int hash = spread(key.hashCode());
int binCount = 0;
//死循环,先获取变量table存在tab中
for (Node<K,V>[] tab = table;;) {
//新建一个node节点记为f
Node<K,V> f; int n, i, fh;
//如果table为null或者length为0就初始化,初始大小16
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//i变量标记key所在位置
//tabAt()返回tab中索引为i的内容,赋值给f判断是否为空
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//如果是空的就用CAS的原子性操作进行插入
//操作是:判断table中i位置的值是null,就把新的node节点插入位置i
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//将节点f的hash值赋值给fh,正常情况下hash是>=0的
//hash为负值的时候有其他意义:表在扩容的时候,老表迁移一个桶需要放一个标记节点(ForingingNode节点)这个Node节点的hash值它固定是-1.
//MOVED就是-1,这里判断的是f节点是否在进行数据迁移
else if ((fh = f.hash) == MOVED)
//执行helpTransfer,顾名思义就是帮助老表进行数据迁移
//如果这个节点正在进行扩容,那么这个线程就会去获取任务,帮助扩容
tab = helpTransfer(tab, f);
else {
//定义老val并设为空值
V oldVal = null;
//对节点f上锁
synchronized (f) {
//如果table的i位置还是f的话,这应该是一步保险操作
if (tabAt(tab, i) == f) {
//如果f节点的hash值>=0
if (fh >= 0) {
binCount = 1;
//将节点f赋值给e
for (Node<K,V> e = f;; ++binCount) {
K ek;
//判断e.hash和要插入的hash是否相同,并且判断他们是否为同样的值。
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;
}
}
}
addCount(1L, binCount);
return null;
}
以上是关于concurrentHashMap源码解析的主要内容,如果未能解决你的问题,请参考以下文章
ConcurrentHashMap源码解析_04 transfer方法源码分析(难点)