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 = 参与扩容线程数
读写阻塞 扩容期间阻塞所有操作 扩容期间读写几乎无感知
相关推荐
JL154 小时前
Spring Boot vs Gin:Java 人搭第一个 Go REST API
java·spring boot·gin
神明不懂浪漫4 小时前
【第七章】Java中的常用类
java·开发语言·前端·经验分享·笔记
程序喵大人13 小时前
【C++进阶】STL容器与迭代器 - 01 STL 容器先解决元素放在哪里
开发语言·c++·stl
cui_ruicheng13 小时前
Python从入门到实战(十六):多进程编程
开发语言·python
Jelena1577958579214 小时前
电商运营分析数据比价接口实战:多平台价格监控与智能决策系统
java·大数据·数据库
wdfk_prog14 小时前
嵌入式面试真题第 15 题:不可恢复异常后的通用崩溃快照、调用栈保存与离线分析架构
linux·开发语言·面试·架构
晴空了无痕14 小时前
从 Go 基础到 K8s:一条可落地的 Go 服务端成长路线
开发语言·后端·golang·kubernetes
神明不懂浪漫14 小时前
【第五章】Java中的继承与多态
java·开发语言
神州世通15 小时前
解密企业通信安全防线:Avaya Aura 三层安全架构深度解析
开发语言·php
AC赳赳老秦16 小时前
企业工商公开信息采集分析:OpenClaw 批量查询企业工商信息,生成企业画像报告
大数据·开发语言·python·自动化·php·deepseek·openclaw