ConcurrentHashMap1.8 多线程扩容机制

ConcurrentHashMap 1.8 彻底重构了扩容逻辑,抛弃了 1.7 的分段锁 + 全表单线程扩容 ,采用无锁 + CAS + 细粒度锁 实现多线程并行扩容,把扩容性能瓶颈从 O (n) 压到极致,是高并发场景下的核心优化。

我用极简原理 + 核心流程 + 关键细节的方式,清晰拆解这套高效扩容机制:


一、核心设计:为什么 1.8 扩容能做到高效?

  1. 数据结构升级:数组 + 链表 / 红黑树,不再是 Segment 分段锁
  2. 扩容核心思想不阻塞写操作 + 多线程分摊迁移任务
  3. 关键标识 :用sizeCtl控制扩容状态、用transferIndex分配迁移桶
  4. 最小迁移单元一个桶(链表 / 红黑树),线程只锁当前桶,不锁全表

二、核心扩容变量(看懂这 4 个变量就懂了扩容)

变量 作用
sizeCtl 扩容状态控制:-1 = 正在初始化;<0 = 多线程扩容中(-N 代表 N 个线程);>0 = 下一次扩容阈值
transferIndex 待迁移桶的起始索引,线程通过 CAS 抢占迁移任务,保证不重复、不遗漏
nextTable 扩容后的新数组(容量是原数组 2 倍),扩容完成后替换原 table
fwd 节点(ForwardingNode) 标记当前桶已迁移完成,其他线程访问会被引导去新数组操作

三、多线程并行扩容完整流程(最核心)

1. 触发扩容

  • 元素个数达到阈值sizeCtl
  • 单个桶链表长度≥8 且数组长度 < 64
  • 写线程(put/remove)发现扩容中,自动协助扩容(核心:无专门扩容线程,业务线程兼职扩容)

2. 初始化扩容(第一个触发扩容的线程)

  1. CAS 修改sizeCtl-1,独占初始化权
  2. 创建nextTable(容量 = 原容量 ×2)
  3. 设置transferIndex=原容量(从最后一个桶往前迁移)
  4. 重置sizeCtl-(1 + 参与扩容的线程数),标记扩容开始

3. 多线程抢占迁移任务(并行核心)

  1. 所有业务线程(put/get/remove)发现扩容,都会加入协助扩容
  2. 线程通过CAS 修改 transferIndex,批量领取迁移桶(默认一次领取 16 个)
  3. 领取规则:从后往前,每个桶只被一个线程迁移,无竞争
  4. 所有线程分摊迁移任务,容量越大,并行效率越高

4. 单桶迁移逻辑(无锁 + 最小粒度锁)

  1. 线程获取当前桶的头节点,加 synchronized 锁(只锁头节点)
  2. 把当前桶的链表 / 红黑树拆分成 2 份
    • 低桶:hash & 原容量 == 0 → 留在新数组原位置
    • 高桶:hash & 原容量 != 0 → 迁移到「原位置 + 原容量」
  3. 迁移完成后,将原桶置为fwd 节点,标记完成
  4. 释放锁,继续迁移下一个桶

5. 扩容期间的读写操作(完全不阻塞)

  • 读操作 :遇到 fwd 节点,直接去nextTable读取,无锁
  • 写操作 :遇到 fwd 节点,协助扩容,再执行写入
  • 只有正在迁移的桶会加锁,其他桶完全并行

6. 扩容完成

  1. 所有桶迁移完毕
  2. table指向nextTable
  3. 重置sizeCtl为新阈值(新容量 ×0.75)
  4. 销毁临时变量,扩容结束

四、1.8 多线程扩容的 3 个革命性优化

1. 业务线程兼职扩容,无单独扩容线程

不用等待后台线程扩容,所有线程一起加速,容量越大越快。

2. 最小粒度锁,无全表阻塞

只锁迁移中的桶头节点,99% 的操作无锁并行,并发能力爆炸。

3. 迁移过程无阻塞读写

读操作无缝跳转新数组,写操作协助扩容,彻底解决 1.7 单线程扩容的性能瓶颈


五、对比 1.7:性能差距有多大?

特性 JDK 1.7 ConcurrentHashMap JDK 1.8 ConcurrentHashMap
扩容方式 单线程全表迁移,全程阻塞 多线程并行迁移,无全表阻塞
锁粒度 Segment 分段锁 桶头节点 synchronized + CAS
扩容性能 O (n),高并发严重卡顿 O (n/M),M = 参与扩容线程数
读写阻塞 扩容期间阻塞所有操作 扩容期间读写几乎无感知
相关推荐
东离与糖宝2 小时前
不用Python!Java+Spring AI 3.x本地RAG系统搭建实战
java·人工智能
堕2742 小时前
JavaEE初阶——《多线程--. 多线程带来的的⻛险-线程安全 (重点)》
java·算法·java-ee
book123_0_992 小时前
spring 跨域CORS Filter
java·后端·spring
空空潍2 小时前
Spring AI 实战教程(一)入门示例
java·后端·spring·ai
星辰_mya2 小时前
自定义注解 + AOP:打造企业级通用组件(日志、限流、幂等)
java·开发语言·spring·面试·架构师
大阿明2 小时前
Go基础之环境搭建
开发语言·后端·golang
polaris06302 小时前
springboot接入deepseek深度求索 java
java·spring boot·后端
真实的菜2 小时前
Spring Boot 升级全攻略:从 2.2 到 2.7 再到 3.x
java·spring boot·后端