ConcurrentHashMap get put方法解析(借鉴大神的和理解的)

时间:2019-10-23
本文章向大家介绍ConcurrentHashMap get put方法解析(借鉴大神的和理解的),主要包括ConcurrentHashMap get put方法解析(借鉴大神的和理解的)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

原文出处 https://blog.csdn.net/liaob0106/article/details/91878302

首先把那些恶心的变量解释一下

变量名称 含义
bincount table里目标索引链表的元素个数
f table里目标索引对应链表的头结点
n table的长度
i 目标索引
fh 头结点f的哈希值
tab table数组的副本

put方法:

final V putVal(K key, V value, boolean onlyIfAbsent) {
//1、判断key是否为空
if (key == null || value == null) throw new NullPointerException();
//2、计算哈希值
int hash = spread(key.hashCode());
int binCount = 0;
//3、得到table的数组
for (Node<K, V>[] tab = table; ; ) {

        Node<K, V> f;
        int n, i, fh;

//4.如果table数组为空,则初始化table
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//5.如果对应key的哈希值上对应table数组下标的位置没有node,则通过cas操作创建一个node放入table中,然后putval出栈
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K, V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//6、如果table正在扩容,则得到扩容后的table,然后再重新开始一个循环
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
//7.到这里说明找到了key hash后对应的table,并且table上有其他node的存在
V oldVal = null;
//8、把这个找到的node加上同步锁,防止并发出现的问题,如果其他key put进来的时候也对应这个tab则堵塞在这里
synchronized (f) {
//9.再次用cas确认索引i上的table为我们找到的node,如果不是的话则这个node被修改,直接释放锁进入下一个循环
if (tabAt(tab, i) == f) {
//10.如果目标table的第一个node的哈希值大于等于0,则是链式结构,走链表查找,反之走红黑树查找
if (fh >= 0) {
//11.标志bincount为1,因为在该table上至少有一个node节点
binCount = 1;
//12.循环链表
for (Node<K, V> e = f; ; ++binCount) {
K ek;
//13.如果遍历元素的哈希值与需要插入目标key的哈希值相同,并且值也相同,则插入的是重复key的元素
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
//14.如果onlyIfAbsent为false的话,则替换为新value,否则不修改(一般传false)
if (!onlyIfAbsent)
e.val = value;
//15.break循环
break;
}
//16.循环直到最后一个node节点的key都不是我们想要插入的key
Node<K, V> pred = e;
if ((e = e.next) == null) {
//在尾部添加一个新节点,break循环
pred.next = new Node<K, V>(hash, key,
value, null);
break;
}
}
}
//17.该节点属于红黑树的子节点,进行树操作
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;
}
}
}
}
//18.如果node节点不为0
if (binCount != 0) {
//19.如果node大于或者等于8,则转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
//20.返回原来key对应的旧值
if (oldVal != null)
return oldVal;
break;
}
}
}
//20.进行扩容判断
addCount(1L, binCount);
return null;
}

get方法:
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
//根据这个key算hashcode 与1.7相比没有异或四次 效率更高了
int h = spread(key.hashCode());
//整个 hashtable对象 table中 tabAt 根据这个key算出来的hash值找对应的value 不为空,看找到的e 返回e的值 。
//由于tab这个节点的val变量是被 volatile修饰 重新赋值(单纯赋值不含任何计算)会被其他线程所知晓。所以get方法不用加锁。
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
return e.val;
}
else if (eh < 0)
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;
}
好文要顶

原文地址:https://www.cnblogs.com/cloudHui/p/11728515.html