当前位置: 首页 > news >正文

Java 并发容器:ConcurrentHashMap 笔记(JDK 1.8)

ConcurrentHashMap 是 Java 提供的一种高效、线程安全的哈希表实现,主要用于多线程环境下替代传统的 HashMapHashtable


1. 基本概念

  • 所在包:java.util.concurrent
  • 线程安全: 是(高效)
  • 是否支持 null 键/值: 不支持(会抛出 NullPointerException
  • JDK 1.8 中采用锁分离 + CAS + 红黑树优化方案

2. 数据结构

JDK 1.8 中 ConcurrentHashMap 的底层结构如下:

transient volatile Node<K,V>[] table;
  • 底层是一个哈希数组,数组中的每个位置是一个链表或红黑树
  • 每个桶位的节点类型为 Node<K,V>TreeNode<K,V>(红黑树节点);
  • 节点结构:
static class Node<K,V> {final int hash;final K key;volatile V val;volatile Node<K,V> next;
}

3. 线程安全机制

核心特性:分段锁 + CAS + synchronized 组合

操作机制说明
put(无冲突)CAS(无锁)
put(冲突)synchronized 锁定链表或树头节点
get无锁(只读 volatile)
扩容synchronized + 多线程协作
红黑树转换synchronized + TreeBin 封装

详细锁机制说明:

1. CAS 操作(乐观锁)
  • 用于插入首节点、创建 table 等;
  • 通过 Unsafe.compareAndSwapObject 保证原子性;
  • 高性能,失败时重试。
2. synchronized 锁节点
  • 当 CAS 无法完成时(如链表存在),对桶头节点加锁
  • 范围非常小,仅锁当前链表,称为“细粒度锁”。
3. volatile 可见性
  • 所有关键字段都用 volatile 修饰,确保多线程间可见性。

4. put 操作流程

步骤简述:

1. 如果 table 未初始化,初始化 table(CAS)
2. 计算 key 的 hash,定位 bucket
3. 如果 bucket 为空,使用 CAS 插入
4. 如果不为空,使用 synchronized 加锁链表或红黑树头节点:- 查找是否存在 key,若存在更新- 若不存在,插入新节点
5. 判断链表长度是否超过阈值(8),转换为红黑树
6. 判断当前元素数量是否超过负载因子,触发扩容

5. 红黑树支持

  • 链表长度超过 8,且数组长度 ≥ 64 ⇒ 转为红黑树
  • 优点:避免链表退化为 O(n)
  • 使用 TreeBin 管理红黑树(不是直接用 TreeMap

6. 扩容机制

与 HashMap 不同:

  • HashMap:单线程扩容,可能死循环(JDK1.7);
  • ConcurrentHashMap:多线程协作扩容,无锁数据迁移。

关键点:

  • transfer() 方法使用 ForwardingNode 作为占位标记,避免并发冲突;
  • 线程在不同 bucket 上迁移,不重复工作;
  • 保证并发场景下的稳定性和安全性。

7. get 操作流程(无锁)

  1. 计算 hash 定位 bucket;
  2. 顺序遍历链表或红黑树;
  3. 比较 key 值,返回 value;
  4. 所有节点使用 volatile,保证可见性。

8. 常用方法说明

方法是否线程安全说明
get(K key)无锁读取
put(K key, V value)CAS + synchronized 组合
remove(K key)加锁删除
computeIfAbsent()函数式接口并发安全支持
forEach()是(弱一致性)遍历过程支持并发修改

9. ConcurrentHashMap vs HashMap vs Hashtable

特性HashMapHashtableConcurrentHashMap
线程安全是(全方法加锁)是(分段+CAS+synchronized)
性能高(单线程)低(锁粒度粗)高(并发环境)
null 支持✅ 允许 null键和值❌ 不允许❌ 不允许
遍历时安全❌ 结构变会抛异常❌ 不 fail-fast✅ 弱一致性
使用推荐场景单线程场景已淘汰并发读写(推荐)

10. 注意事项和建议

  • 不支持 null 作为 key 或 value;
  • 遍历期间可以安全地并发修改(弱一致性);
  • 不保证元素顺序;
  • 适用于高并发缓存、共享数据容器;
  • 如果要强一致遍历,建议使用 synchronized 或加快写入频率控制。

11. 总结

优点说明
高效线程安全分段锁+CAS+synchronized 保证效率与安全
支持高并发多线程读写性能远高于 Hashtable
局部加锁,粒度细每次只锁单个桶位,不影响整体性能
支持红黑树优化高冲突场景避免链表退化,保持高查找性能
支持多线程扩容扩容性能高,避免阻塞

12. JDK 1.7 vs JDK 1.8:ConcurrentHashMap 实现对比

对比维度JDK 1.7 实现(老版)JDK 1.8 实现(现代)
底层结构Segment 数组 + HashEntry[]Node[] 数组(无 Segment)
锁粒度Segment 锁(分段锁,16 段默认)桶位节点锁(更细,基于 synchronized)
锁类型显式悲观锁(ReentrantLock)CAS + synchronized(乐观 + 悲观)
并发扩容不支持,扩容时阻塞整个表支持多线程协作扩容
红黑树优化不支持,链表可能退化为 O(n)支持链表转红黑树,保持查询高效
put/get 过程需定位 Segment,再定位桶直接定位数组桶,减少层级
初始化机制使用 final Segment[] 延迟初始化使用 CAS 创建 table,按需初始化
遍历一致性弱一致性弱一致性(更快)
null 支持不支持不支持
性能和扩展性并发度受限于 Segment 数性能更优,适用于更高并发

总结:

  • JDK 1.7:通过「Segment 分段锁」实现线程安全,锁粒度为段,缺点是扩容时性能差、冲突严重时链表长;
  • JDK 1.8:摒弃 Segment,采用「数组 + CAS + synchronized + 红黑树」架构,锁更细、效率更高、并发性能显著提升
http://www.dtcms.com/a/296845.html

相关文章:

  • 01_FOC学习之先让电机转动起来
  • 双紫擒龙紫紫红黄安装使用攻略,2025通达信指标源码,擒龙追踪源码公式学习
  • 爬虫基础概念
  • 浏览器访问[http://www.taobao.com](http://www.taobao.com/),经历了怎样的过程。
  • DNS域名解析过程
  • 通达OA二次开发
  • Impact rating 影响等级定义(学习笔记)
  • YOLOv8 剪枝模型加载踩坑记:解决 YAML 覆盖剪枝结构的问题
  • 【JAVA】使用vosk实现windows实时语音转文字,解放双手
  • vs2019 创建MFC ActiveX的详细步骤
  • JS事件基础
  • ESP-NOW无线通信协议:物联网设备间的高效对话方式
  • 前端基础知识Vue系列 - 24(axios的原理)
  • Linux(centos7)安装 docker + ollama+ deepseek-r1:7b + Open WebUI(内含一键安装脚本)
  • Windows下使用UIAutomation技术遍历桌面窗口和指定窗口内容的AutomationWalker.exe的C#源代码
  • QT元对象系统-(1)静态属性和动态属性
  • Jenkins配置与应用指南
  • 外贸公司经营步骤
  • AI赋能软件工程让测试左移更加可实施
  • 《C++》面向对象编程--类(下)
  • IPv6网络优化
  • ANSYS Fluent 管内流动仿真
  • 如何恢复mysql,避免被研发删库跑路
  • Python(09)正则表达式
  • 无人机云台跟踪目标实现
  • springboot项目建立sse接口
  • tokenID和位置嵌入有关系吗,qwen 模型使用时候仅仅有tokenid 映射为向量,位置编码在哪里
  • C++的虚基类?
  • 黑马头条项目详解
  • cmake应用:集成gtest进行单元测试