本文目录导读:

ConcurrentHashMap 的分段锁机制是 Java 7 及之前版本中的核心设计(Java 8 之后改用 CAS + synchronized + 红黑树 来优化锁粒度),分段锁的核心思想是:将数据分片,分别加锁,从而提高并发效率。
下面先详细解释 Java 7 的分段锁原理,再说明 Java 8 的改进。
Java 7 中的分段锁(Segment)
数据结构
- 整个
ConcurrentHashMap由一个 Segment 数组 构成。 - 每个
Segment本身就是一个 小型 HashMap(内部包含一个HashEntry数组)。 - 每个
Segment继承自ReentrantLock(可重入锁),即每个 Segment 拥有自己的锁。
示意图:
ConcurrentHashMap
├── Segment[0] (锁1)
│ ├── HashEntry[0]
│ ├── HashEntry[1]
│ └── ...
├── Segment[1] (锁2)
│ ├── HashEntry[0]
│ └── ...
├── ...
└── Segment[15] (锁16) // 默认16个Segment
锁的粒度
- 默认并发级别:16(即 16 个 Segment)。
- 锁的粒度:一个锁只保护一个 Segment 内的所有 HashEntry。
- 不同的 Segment 之间 完全独立,可以同时被不同线程访问。
读写操作流程
put 操作
// 简化逻辑
public V put(K key, V value) {
int hash = hash(key);
int segmentIndex = (hash >>> segmentShift) & segmentMask;
Segment<K,V> s = segments[segmentIndex];
// 对单个 Segment 加锁(可重入锁)
s.lock();
try {
// 在 Segment 内部的 HashEntry 数组中插入或更新
// 每个 Segment 内部与 HashMap 类似
} finally {
s.unlock();
}
}
- 只锁一个 Segment,其他 15 个 Segment 完全不受影响,可被其他线程并发操作。
get 操作
public V get(Object key) {
int hash = hash(key);
int segmentIndex = (hash >>> segmentShift) & segmentMask;
Segment<K,V> s = segments[segmentIndex];
// get 操作不加锁,依靠 volatile 关键字保证可见性
// HashEntry 的 value 字段是 volatile 的
HashEntry<K,V> e = s.getEntry(hash, key);
return e == null ? null : e.value;
}
- get 不加锁,因此读取效率极高。
- 通过
volatile保证:读线程一定能看到其他线程写入的最新值。
size 操作
- 需要获取所有 Segment 的大小之和。
- 不加锁的尝试:先不加锁累加两次。
- 如果两次结果一致,则直接返回。
- 如果不一致,则 锁住所有 Segment 再计算。
分段锁的优势
| 特性 | 普通 HashMap(线程不安全) | Hashtable / Collections.synchronizedMap | ConcurrentHashMap(分段锁) |
|---|---|---|---|
| 锁粒度 | 无 | 整张表一把锁 | 每个 Segment 一把锁 |
| 并发读写 | 线程不安全 | 完全串行,效率低 | 不同 Segment 可并发 |
| 读操作 | 无锁 | 加锁 | 无锁(volatile) |
核心优势:在多线程环境下,多个线程可以同时写入不同的 Segment,极大提升吞吐量。
Java 8 的改进:放弃分段锁
Java 8 对 ConcurrentHashMap 进行了重构,不再使用 Segment,而是改为:
新的数据结构
- 内部直接使用 Node 数组 + 链表 / 红黑树(与 HashMap 类似)。
- 使用 synchronized + CAS 实现并发控制。
锁粒度更细
- 锁的粒度:从“一个 Segment” 降为 “一个桶(bucket)”(即数组的一个位置)。
- 当多个线程操作不同的哈希桶时,可以完全并发,无需竞争同一把锁。
实现方式
- put 操作:
- 如果桶为空:使用 CAS 无锁插入。
- 如果桶不为空:对该桶的 头节点加 synchronized 锁,然后遍历链表/红黑树。
- get 操作:完全无锁,通过 volatile 保证可见性。
- 扩容:支持 多线程协助扩容(transfer),而不是像 Java 7 那样锁住整个 Segment。
为什么比分段锁更好?
- 锁粒度更细:分段锁最多 16 个并发写入(默认),Java 8 理论上可以支持所有桶同时写入(取决于哈希分布)。
- 内存占用更小:不需要维护 Segment 数组和额外的锁对象。
- 查询效率更高:红黑树将最坏情况从 O(n) 降为 O(log n)。
总结与对比
| 版本 | 锁机制 | 锁粒度 | 并发写入上限 | 读操作锁 |
|---|---|---|---|---|
| Java 7 | Segment 继承 ReentrantLock | 每个 Segment | 默认 16 | 无锁(volatile) |
| Java 8 | CAS + synchronized | 每个哈希桶 | 理论所有桶 | 无锁(volatile) |
- Java 7 分段锁:把 Map 分成若干段,每段一把锁,不同段可并发。
- Java 8 改进:去掉分段,直接用 CAS 和桶级锁(synchronized),粒度更细、性能更好、内存更低。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播