ConcurrentHashMap 原理分析

ConcurrentHashMap 是 jdk 提供的针对并发环境下的集合类容器,是为了解决 HashMap 在并发环境下的线程安全问题。

JDK7

  • 利用分段锁(Segment)和 ReentrantLock 类实现并发控制的,类中维护了一组 Segment,通过对 key 进行 hash 获取相应的 Segment,Segment 内部维护了一组 HashEntry,类似 HashMap 结构,并且在并发修改阶段对管程进行加锁控制。

  • size() 方法使用的是遍历 Segment 加锁获取,在获取大小的时候会影响数据的修改。

JDK8

而 jdk8 中 ConcurrentHashMap 具体的变化有:

  • 不在使用分段锁,而是恢复成与 HashMap 相似的结构。

  • 对 hash 算法进行改进,使用高位移到低位异或,避免哈希碰撞。原因是 jdk 的哈希寻址是使用低位,而有些数据的哈希值差异主要在高位。

  • 使用链表加红黑树的数据结构进行存储,哈希碰撞时使用链表,当链表长度大于 8 时,将当前链表的数据结构变形为红黑树,这样做的目的是为了解决当链表长度过大而造成的查询开销。

  • 对数据的修改使用了 CAS 和 sychronized 进行并发控制,原因是 sychronized 在近代 JVM中 已经经过大量优化,性能与 ReentrantLock 差距不大,放弃使用 ReentrantLock 一方面能够节省的内存开销,另一方面能够降低开发成本。

  • 使用了类似 LongAdder 的数据结构存储大小,并使用了缓存行填充。

  • 避免初始开销,延迟加载数据结构。