ConcurrentHashMap中的get和put源码分析
2022/9/1 1:22:57
本文主要是介绍ConcurrentHashMap中的get和put源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
get分析
public V get(Object key) { // tab:指向数组 Node<K,V>[] tab; // e:指向key对应的Node节点、p: Node<K,V> e, p; // n:数组长度、eh:key对应节点的哈希值 int n, eh; // ek:key对应节点的key K ek; // h:根据传入的key获取对应hash值 int h = spread(key.hashCode()); // 检测tab数组不为null、tab数组长度大于0、检测key是否存在对应的Node节点 if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { // 检测当前指向的Node节点的哈希值是否和传入key的哈希值是否一致、一致则返回对应的值、不一致则在链表或者红黑树中查找对应的Node节点。 if ((eh = e.hash) == h) { // 检测当前Node节点的key和传入的key是否一致、使用地址判断或者equals判断、一致则返回key对应的value值 if ((ek = e.key) == key || (ek != null && key.equals(ek))) // 返回对应Node节点的value值 return e.val; } // 红黑树查找、哈希小于0则代表Node是 TreeNode节点、调用find内部在调用findTreeNode查找对应的节点值 //eh=-1,说明该节点是一个ForwardingNode,正在迁移,此时调用ForwardingNode的find方法去nextTable里找。 //eh=-2,说明该节点是一个TreeBin,此时调用TreeBin的find方法遍历红黑树,由于红黑树有可能正在旋转变色,所以find里会有读写锁。 //eh>=0,说明该节点下挂的是一个链表,直接遍历该链表即可。 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; }
put分析
public V put(K key, V value) { // 具体实现、false表示更新数据、ture则不更新数据、既put只新增不修改 return putVal(key, value, false); } final V putVal(K key, V value, boolean onlyIfAbsent) { // key或者value为null则抛出异常 if (key == null || value == null) throw new NullPointerException(); // hash: key的哈希值 int hash = spread(key.hashCode()); // binCount: 用于检测链表长度、大于8时转换为红黑树 int binCount = 0; for (Node<K,V>[] tab = table;;) { // f: 指向key哈希值所在数组中的Node节点 Node<K,V> f; // n:数组的长度 // i:key哈希值所在数组中的索引 // fh:Node节点的哈希值 int n, i, fh; // 检测数组是否为null、长度为0 if (tab == null || (n = tab.length) == 0) // 初始化数组 tab = initTable(); // 当前key哈希值所在数组中不存在Node节点 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { // 创建一个Node节点到数组中、指定数组索引位置 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) == MOVED) tab = helpTransfer(tab, f); else { // 将值写入到链表或者红黑树中 V oldVal = null; // 传入Node节点作为同步对象 synchronized (f) { // 再次检测一下Node节点是否有变化 if (tabAt(tab, i) == f) { // if (fh >= 0) { // 链表节点数 binCount = 1; for (Node<K,V> e = f;; ++binCount) { // 指向Node节点的key K ek; // 判断hash和key是否一致 if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; if (!onlyIfAbsent) // 修改key对应的值 e.val = value; break; } // 代表不一致、查询是否有下一个节点、没有则创建Node节点、有则继续循环、检测是修改Node节点还是创建Node节点 Node<K,V> pred = e; // 检测当前Node节点的下一个节点是否为空、为空则创建、不为空继续检测 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) { // 链表长度大于8时、将链表转换为红黑树 if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) // 返回被修改的值 return oldVal; break; } } } addCount(1L, binCount); return null; }
这篇关于ConcurrentHashMap中的get和put源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享
- 2024-11-22ansible 的archive 参数是什么意思?-icode9专业技术文章分享
- 2024-11-22ansible 中怎么只用archive 排除某个目录?-icode9专业技术文章分享
- 2024-11-22exclude_path参数是什么作用?-icode9专业技术文章分享
- 2024-11-22微信开放平台第三方平台什么时候调用数据预拉取和数据周期性更新接口?-icode9专业技术文章分享
- 2024-11-22uniapp 实现聊天消息会话的列表功能怎么实现?-icode9专业技术文章分享
- 2024-11-22在Mac系统上将图片中的文字提取出来有哪些方法?-icode9专业技术文章分享
- 2024-11-22excel 表格中怎么固定一行显示不滚动?-icode9专业技术文章分享
- 2024-11-22怎么将 -rwxr-xr-x 修改为 drwxr-xr-x?-icode9专业技术文章分享
- 2024-11-22在Excel中怎么将小数向上取整到最接近的整数?-icode9专业技术文章分享