概述
有了前文的基础,直接看到get方法
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
//计算hash值
int h = spread(key.hashCode());
//如果table初始化过 且 根据hash定位到对应位置的table上有数据
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
//判断头部数据的hash 和 key 和传入的数据是否一致
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
//一致直接返回该值
return e.val;
}
//如果是树节点,或者该节点已经被迁移到新的table上 这里只看ForwardingNode的find方法,不看树的相关操作了
else if (eh < 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;
}
}
//找不到,返回null
return null;
}
ForwardingNode的find方法
static final class ForwardingNode<K,V> extends Node<K,V> {
final Node<K,V>[] nextTable;
ForwardingNode(Node<K,V>[] tab) {
super(MOVED, null, null, null);
this.nextTable = tab;
}
Node<K,V> find(int h, Object k) {
// loop to avoid arbitrarily deep recursion on forwarding nodes
//从新的table上查找数据
outer: for (Node<K,V>[] tab = nextTable;;) {
Node<K,V> e; int n;
//如果新的table的对应位置上的节点为空,直接返回空
if (k == null || tab == null || (n = tab.length) == 0 ||
(e = tabAt(tab, (n - 1) & h)) == null)
return null;
//该位置上有值,在该位置查找数据
for (;;) {
int eh; K ek;
//如果头节点符合要求,直接返回头节点
if ((eh = e.hash) == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
//如果是树节点,或者该节点已经被迁移到新的table上
if (eh < 0) {
if (e instanceof ForwardingNode) {
//获取到新的table,重新循环查找
tab = ((ForwardingNode<K,V>)e).nextTable;
continue outer;
}
//从树中查找节点
else
return e.find(h, k);
}
//如果下一个节点为空,直接返回空
//否则,接着判断下一个节点是否满足条件
if ((e = e.next) == null)
return null;
}
}
}
}
再来看到remove方法
public V remove(Object key) {
//调用的replaceNode方法,后两个参数为空
return replaceNode(key, null, null);
}
final V replaceNode(Object key, V value, Object cv) {
//获取hash
int hash = spread(key.hashCode());
//死循环
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//table 还未初始化, 或者table对应位置(i)上没有数据 ,直接break
if (tab == null || (n = tab.length) == 0 ||
(f = tabAt(tab, i = (n - 1) & hash)) == null)
break;
//如果该节点已经被迁移到新的table上,则尝试帮助迁移
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
boolean validated = false;
//锁住table对应位置的头节点
synchronized (f) {
//获取到i位置的头节点,如果没有发生改变
if (tabAt(tab, i) == f) {
//从链表上找
if (fh >= 0) {
//validated 修改为true
validated = true;
//死循环
for (Node<K,V> e = f, pred = null;;) {
K ek;
//如果找到了对应的节点
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
//获取节点的value为 ev
V ev = e.val;
//入参cv为空 或者 ev和cv 或者 节点的值不为空 或者cv equals ev
if (cv == null || cv == ev ||
(ev != null && cv.equals(ev))) {
//oldVal保存ev的值
oldVal = ev;
//入参的value不为空
if (value != null)
//将该节点的value替换为入参的value
e.val = value;
//如果有前一个节点(不是头节点)
else if (pred != null)
//将当前节点从链表中断开
pred.next = e.next;
//如果是头节点,直接将头节点设置为下一个节点
else
setTabAt(tab, i, e.next);
}
//跳出循环
break;
}
//pred记录前一个节点
pred = e;
//e修改为下一个节点,下一个节点为空,则break循环结束
if ((e = e.next) == null)
break;
}
}
//从树中找
else if (f instanceof TreeBin) {
//validated 修改为true
validated = true;
TreeBin<K,V> t = (TreeBin<K,V>)f;
TreeNode<K,V> r, p;
//从树中查找节点
if ((r = t.root) != null &&
(p = r.findTreeNode(hash, key, null)) != null) {
V pv = p.val;
if (cv == null || cv == pv ||
(pv != null && cv.equals(pv))) {
oldVal = pv;
if (value != null)
p.val = value;
//从树中删除节点,返回true说明树中节点数过少
else if (t.removeTreeNode(p))
//降级为链表,设置回table中
setTabAt(tab, i, untreeify(t.first));
}
}
}
}
}
//如果validated为true
if (validated) {
//如果oldVal 不为空,返回oldVal
if (oldVal != null) {
if (value == null)
//对baseCount或者counterCell的值减一
addCount(-1L, -1);
return oldVal;
}
break;
}
}
}
return null;
}
最后
以上就是瘦瘦毛豆为你收集整理的ConcurrentHashMap源码分析(二) ---- get方法和remove方法的全部内容,希望文章能够帮你解决ConcurrentHashMap源码分析(二) ---- get方法和remove方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复