一、序言
本文和大家探讨一下 ConcurrentHashMap#get()
方法的源码。
二、源码概览
public V get(Object key) {
// 定义变量
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
// 计算键的哈希值
int h = spread(key.hashCode());
// 检查哈希表是否为空,并找到键对应的节点
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;
}
// 如果节点的哈希值小于 0,就调用 find 方法来查找节点,
// 如果找到了就返回对应的值,否则返回 null
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;
}
}
// 如果在哈希表中没有找到给定的键,那么就返回 null
return null;
}
上述代码是 ConcurrentHashMap#get()
方法的源码。
三、源码流程分析
我们可以分析出 ConcurrentHashMap#get()
的工作流程是:
- 首先,通过调用 spread() 方法计算 Hash 值
- 然后,检查哈希表和要查找的键所对应的节点是否为 null
- 如果不为 null,进一步检查该位置节点的哈希值是否与要查找的键的哈希值相等,如果相等,则直接返回该节点的值。
- 如果哈希值不相等,但是该位置节点的哈希值小于 0,说明该位置的节点是红黑树,则调用节点的
find()
方法进行查找,返回对应键的节点。 - 如果以上情况都不满足,说明该位置的节点是一个链表结构,则进行链表遍历,查找与给定键相等的节点,找到则返回对应的值。
- 如果遍历完链表仍未找到匹配的键,则返回 null。
通过上面的工作流程分析,我们可以总结出其核心流程为:
- 计算出哈希值
- 哈希值相等键也相等则直接返回 value
- 哈希值小于 0,使用
find()
在红黑树中查找,找到返回 value - 其他情况在链表中查找,找到返回 value
- 如果没有找到值就返回
null
往期推荐
- ConcurrentHashMap 源码分析(一)
- IoC 思想简单而深邃
- ThreadLocal
- Spring 三级缓存
- RBAC 权限设计(二)