【Java 快速复习】理解 HashMap & ConcurrentHashMap

HashMap是非线程安全的,采用数组+链表/红黑树实现,负载因子为0.75,当冲突过多时会转换为红黑树。ConcurrentHashMap为线程安全,1.7版本使用分段锁,1.8版本采用CAS和自旋锁实现并发控制,扩容过程更加高效且线程友好。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理解 HashMap & ConcurrentHashMap

首先是 HashMap , HashMap 本质上是数组实现的,思想是通过对 key 计算 hashCode 并将其 hashCode % (array.length - 1) 来计算要放到哪个位置。

Java 在设计 HashMap 的时候是这样设计的:

  1. Node<K,V>[] table; 数组承载数据
  2. 限制数组大小必须为 2^n 并基于此优化计算槽位算法为位运算 hash & (length -1)
  3. hash 值高低位扰动,增加随机性降低 hash 冲突概率
  4. 出现哈希冲突时进行拉链,即 数组 + 链表 (1.8 后引入红黑树,当链表大于 8 个节点时会将结构优化为红黑树加快查询效率 logN)
  5. 负载因子 0.75 ,即数组内元素到达数组长度 75% 时进行扩容 (1.7 版本的扩容头插法实现如果在有链表且存在并发扩容的情况有可能会引发链表成环的问题,在 1.8 版本进行了优化改为高低位指针解决了此问题。)

注意 HashMap 线程不安全

线程安全的 HashMap -> HashTable -> ConcurrentHashMap

提一下 HashTable ,其为了线程安全是直接暴力加锁,其 get 和 put 都会直接对当前对象加 synchronized 锁,这个效率是很低的。

所以生产环境基本不会用。

对于 ConcurrentHashMap Java 是这样设计的

  1. 分段锁机制
    1. 1.7 版本 采用的是 二次哈希,大的数组中套小数组 Segment,大数组 hash 后得到槽位,锁当前槽位,对槽位的小数组再进行 hash 最后入表
    2. 1.8 版本的实现基本和 HashMap 一样,在写数据时采用了 自旋 + cas 的方式,也就是说只有当前槽位有数据时才会进行加锁
  2. 扩容
    1. 1.7 类似 HashMap
    2. 1.8 版本利用了多线程的优势,渐进式扩容,会有新旧两个 table ,触发扩容后会扩容部分数据,旧数据会变为 ForwardingNode 且 hash = -1 moved 标记为已移动,如果其他线程在 put 或 remove 时命中了 ForwardingNode 节点会帮助进行扩容,分配扩容区域 ,最少分配 16 个槽位的迁移。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dying 搁浅

两杯酒,一杯敬你余生多欢喜。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值