ConcurrentHashMap(CHM)是Java为解决高并发场景下哈希表性能瓶颈而设计的线程安全容器,其核心目标在于:
- 线程安全:避免多线程操作导致的数据不一致问题;
- 高吞吐量:通过细粒度锁和无锁化设计降低线程竞争;
- 动态扩展:支持自动扩容与数据结构优化(如链表转红黑树);
下面我们一起详细看看ConcurrentHashMap的细节是什么样的
一、ConcurrentHashMap 概述
ConcurrentHashMap(CHM) 是 Java 并发包中实现线程安全的哈希表,其核心设计目标是在高并发场景下兼顾性能与线程安全。与 HashTable 的全表锁不同,CHM 通过分段锁(JDK7)和CAS+synchronized细粒度锁(JDK8+) 实现高效并发控制,解决了传统同步容器的性能瓶颈。
二、核心工作原理
2.1 数据结构的演进
1)JDK7 分段锁机制
- 采用 Segment 数组 + HashEntry 链表 的二级结构,每个 Segment 继承 ReentrantLock,独立管理一个子哈希表。
- 锁粒度:以 Segment 为锁单位,不同 Segment 的写操作可并行。
- 缺点:Segment 数量固定(默认16),扩容仅针对单个 Segment,无法全局动态调整。
2)JDK8+ 优化设计
- Node 数组 + 链表/红黑树:取消 Segment,直接使用 Node 数组,链表长度超过8时转为红黑树(避免哈希冲突导致的性能退化)。
- 锁粒度细化:仅对单个桶(Node 数组元素)加锁(通过 synchronized 和 CAS),并发度更高。
具体版本对比如下
2.2 线程安全机制
1)CAS(Compare And Swap):用于无锁化更新头节点、统计元素数量(如 sizeCtl)等场景,减少线程阻塞。
2)Synchronized 锁:针对具体桶(Node)加锁,仅当哈希冲突时触发,避免全局锁竞争。
3)Volatile 变量:保证内存可见性,如 Node.val 和 next 指针均用 volatile 修饰。
2.3 JDK8实现原理和源码解析
1)核心数据结构
// Node节点定义(链表结构)
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; volatile V val; // 保证可见性 volatile Node<K,V> next; // 保证可见性 // ...
} // TreeNode节点(红黑树结构)
static final class TreeNode<K,V> extends Node<K,V> { TreeNode<K,V> parent; TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; boolean red;
}
设计要点:
- volatile修饰:val和next字段确保内存可见性;
- 树化