大家好,JDK1.7 HashMap
在并发执行put
操作时会引起死循环,导致CPU利用率接近100%,这个是八股文内容之一,想必各位小伙伴也知道;在问到此问题的时候,可能有些面试官也会让我们讲讲这个死循环发生的过程,小编之前在面试某杭州电商的时候,也被问到过;如果回答不好,可能会被扣分。今天我就带大家一起梳理一下,这个问题是如何产生的。
本篇文章,小编会先从JDK1.7 HashMap底层数据结构
,put()流程
,然后通过图解演示的方式给大家讲解死循环的发生过程。
1.HahsMap数据结构
HashMap
内部维护了一个数组table
,每个元素是一个链表的头结点。链表中存储了具有相同hash值
的键值对。在JDK1.7中,HashMap
中的键值对使用Entry
类表示。Entry
类包含四个属性: key
, value
, hash
值和用于单向链表的next
。
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
// 省略属性的访问get/set方法
}
复制代码
2.PUT流程及扩容机制
总体来说,put
方法的实现比较复杂,涉及到哈希值
的计算、扩容、索引的计算、链表的遍历和修改等多个操作;为了便于理解,工匠先将整个逻辑用流程图的方式给大家呈现出来,然后逐行分析源码,源码分析的地方可能比较长,大家可通过先记流程图,然后看源码解析部分:
2.1 put
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value,