您的位置:首页 >JavaHashMap与ConcurrentHashMap全方位对比
发布于2026-08-06 阅读(0)
扫一扫,手机访问
Entry[] 数组,哈希冲突时往后挂单向链表底层变成了 Node

// 扰动函数,高低位异或,减少哈希碰撞
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
用 (table.length - 1) & hash 定位数组下标,替代了取模运算,效率更高。 2. 冲突处理:
| 参数 | 说明 |
|---|---|
DEFAULT_INITIAL_CAPACITY = 16 | 默认数组容量,必须是 2 的幂 |
MAXIMUM_CAPACITY = 1<<30 | 最大容量 |
DEFAULT_LOAD_FACTOR = 0.75f | 负载因子;元素数量 容量×0.75 触发扩容 |
TREEIFY_THRESHOLD = 8 | 链表转红黑树阈值 |
UNTREEIFY_THRESHOLD = 6 | 红黑树转回链表阈值 |
hash & oldCap == 0:下标不变hash & oldCap != 0:下标 = 原下标 + 旧容量 不需要重新计算哈希值,仅移位即可,效率大幅提升。多线程同时执行 resize,头插法会导致链表节点互相引用形成闭环,get() 遍历链表死循环。
put:数据覆盖,两个线程哈希到同一位置,后插入覆盖先插入的数据;ConcurrentModificationException(迭代器快速失败 fail-fast)。结论:HashMap 严禁多线程环境直接使用。
put(key,value)
get(key) 寻址找到桶,先判断头节点,链表顺序遍历 / 红黑树查找。解决 HashMap 线程不安全,替代 Hashtable(全局 synchronized 锁整个数组,并发极差)。
所有方法加 synchronized 锁住整张哈希表,同一时刻只能一个线程读写,高并发下竞争激烈。
Segment[] 分段数组,每个 Segment 内部是独立的 HashEntry[] 哈希表;ReentrantLock,操作某一段哈希表时只锁住当前 Segment;volatile 修饰核心变量:table 数组、Node 的 val、next,保证可见性,避免缓存不一致。sizeCtl 状态:
table[i] == null:利用 CAS 尝试直接插入新 Node,成功则结束;CAS 失败自旋重试;table[i] != null:ForwardingNode),当前线程协助一起扩容;addCount() CAS 更新元素总数,检查是否触发扩容。volatile 保证节点数据可见性,不加锁,读性能极高。sizeCtl 为扩容标记;ForwardingNode(转发节点),会加入帮忙迁移数据;table 引用。通过 baseCount(基础计数)+ 多个 CounterCell 计数单元,多线程分散计数,减少 CAS 竞争:
HashMap 允许一个 key=null 放在下标 0; ConcurrentHashMap 拒绝 null: 并发场景下无法区分: get(key)==null 是key 不存在,还是key 对应 value 本身就是 null,无锁场景下无法通过二次 containsKey 判断,极易产生并发歧义。
迭代器基于快照遍历,不会抛出 ConcurrentModificationException,迭代期间数据修改能弱感知,不会快速失败。
| 对比维度 | HashMap(JDK8) | ConcurrentHashMap(JDK8) |
|---|---|---|
| 线程安全 | 不安全,并发丢数据、死循环 | 安全,CAS+synchronized 保证 |
| 锁机制 | 无锁 | CAS + 桶头 synchronized |
| 数据结构 | 数组 + 链表 + 红黑树 | 和 HashMap 完全一致 |
| null 值 | key 允许 1 个 null,value 允许 null | key、value 都不允许 null |
| 读操作 | 无锁 | 无锁,volatile 保证可见性 |
| 写并发 | 完全不支持并发写入 | 不同桶可并发写入,同桶串行 |
| 迭代机制 | fail-fast,并发修改抛异常 | fail-safe,基于快照不抛异常 |
| 适用场景 | 单线程环境 | 多线程高并发读写场景 |
| 扩容 | 单线程扩容 | 多线程协助并行扩容 |
平衡哈希冲突概率与空间利用率:
Hashtable:全局锁,性能极差,废弃不推荐;Collections.synchronizedMap(new HashMap()):方法级 synchronized 锁住整个对象,同一时刻仅一线程读写,适合低并发;ConcurrentHashMap:分段细粒度锁,高并发场景首选。头插法 + 多线程同时扩容,新数组迁移时节点引用倒置,两个线程互相引用形成环形链表,get 无限遍历死循环;JDK8 尾插法杜绝环形链表,但数据覆盖问题依旧存在。
synchronized 包裹 HashMap,简单场景够用;size() 是近似值,统计过程中数据还在变更,无法做到绝对精准;computeIfAbsent 这类原子复合操作全程加锁,保证判断 + 赋值原子性;
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8