面试知识库

HashMap → ConcurrentHashMap → 并发集合 追问链#

追问路径#

涉及知识点#

核心串联逻辑#

  1. HashMap结构:数组存Node,hash冲突用链表,链表长度≥8且数组长度≥64时转红黑树(O(n)→O(logn))
  2. 扩容:负载因子0.75触发,容量翻倍;JDK8利用(e.hash & oldCap) == 0判断新位置,无需重算hash
  3. 线程不安全:JDK7头插法并发扩容导致环形链表;JDK8尾插法解决了环但仍有数据覆盖
  4. ConcurrentHashMap演进
    • JDK7:16个Segment,每个Segment是一个小HashMap,并发度=Segment数
    • JDK8:锁粒度细化到Node级别,CAS写baseCount,竞争激烈时用CounterCell分散
  5. 代码示例
    // ConcurrentHashMap JDK8 put核心逻辑
    if (tab[i] == null)
        casTabAt(tab, i, null, new Node<>(hash, key, value)); // CAS写空槽
    else
        synchronized (f) { /* 锁住链表头/树根 */ }
    java

面试回答串联#

30秒速答#

“HashMap底层是数组+链表+红黑树,链表长度≥8转树。多线程不安全,JDK7会死循环。ConcurrentHashMap在JDK8用CAS+synchronized锁单个Node解决并发,size()用CounterCell分散竞争类似LongAdder。“

2分钟展开答#

“HashMap用数组存储Node节点,通过hash值定位数组下标。hash冲突时JDK8用尾插法链表,链表长度≥8且数组≥64时转红黑树,将O(n)查找优化到O(logn)。扩容时容量翻倍,利用高位bit直接判断新位置避免重算hash。多线程下JDK7的头插法扩容会形成环形链表导致死循环,JDK8虽然改用尾插法但仍存在数据覆盖问题。ConcurrentHashMap在JDK8弃用了分段锁,改为对链表头Node加synchronized锁+CAS写空槽,锁粒度从Segment级别细化到Node级别。它的size()方法借鉴LongAdder思想,用baseCount+CounterCell数组分散CAS竞争,还用@Contended注解避免伪共享。“

相关追问链#