ConcurrentHashMap 1.7 vs 1.8:分段锁到 CAS+红黑树的演进与性能差异

原文来自于:zha-ge.cn/java/78

ConcurrentHashMap 1.7 vs 1.8:分段锁到 CAS+红黑树的演进与性能差异

讲真,老程序员都得靠点岁月滤镜。我第一次深扒 ConcurrentHashMap 的源码,还是在 JDK 1.7 时代,那时候的哈希并发魂就是"分段锁",每次和同事聊起,都有点"这玩意多神"的尬自豪。结果等到 1.8 出来,我突然尴尬地发现------这货都变天了!今天,就和大家唠唠我踩过的那些并发哈希坑。


老 ConcurrentHashMap 的分段锁江湖

Java 1.7 的 ConcurrentHashMap 纯粹是"分治思想"的现实写照。它把整个 Map 切成多个 Segment,每个 Segment 都是个小 HashTable,管自己一亩三分地。你 put、get、remove,基本不会打架:

  • 分段锁(Segment):每段一把锁,减少竞争
  • 不支持 null key/null value(冷知识)

比如放数据,大致长这样:

java 复制代码
int hash = hash(key);
int segmentIndex = (hash >>> segmentShift) & segmentMask;
Segment<K,V> s = segments[segmentIndex];
s.lock();
try {
    s.put(key, value);
} finally {
    s.unlock();
}

简化后的意思就是:我锁的只是 Segment,不像 HashTable 那样整个表锁死(所以 HashTable 几乎没人用了...)。


JDK 1.8:演变新世界,CAS+链表+红黑树

到了 1.8,这玩意彻底变了个腔调,"分段锁"拜拜,取而代之的是"桶级别"的操作+一身并发黑科技:

  • 不再有 Segment 数组,只有 Node\[\] table
  • put 的时候,先 CAS 尝试抢占 Node(用 synchronized 兜底)
  • 链表太长自动转红黑树,查找 O(logn) 不是梦

来,来,看核心放数据的套路:

java 复制代码
Node<K,V>[] tab = table;
int i = (n - 1) & hash;
Node<K,V> f = tabAt(tab, i);
if (f == null) {
    if (casTabAt(tab, i, null, newNode)) {
        // CAS抢坑成功,无竞争~
    }
} else {
    synchronized (f) {
        // 操作链表或红黑树,争抢得激烈则自动变树!
    }
}

注:这 tabAtcasTabAt 都是 Unsafe 的骚操作~


踩坑瞬间

我自己曾经经历过一次性能"大地震"。那会儿线上压测,两个不同 JDK 下 ConcurrentHashMap,居然结果天差地别。

痛点回忆:

  • 1.7 多线程 put,性能稳定,但线程数过高还是得拼命锁各个段
  • 1.8 急剧提升高并发下的写吞吐,尤其线程超多时,老版本直接锁段,等得人抓耳挠腮,新版 CAS 猛冲
  • 红黑树救过命:有一回 keys 奇葩碰撞扎堆,1.7 直接挂了链表超长数秒。1.8 自动转树,时间稳定 O(logn),查找都不带卡的

有次还诡异碰到过遍历 ConcurrentHashMap 一边 put 的场景,1.7 下因为 Segment 结构脑壳痛,1.8 基本溜了。


性能小对比

偷偷摸鱼做了下对比:

JDK 高并发写延迟 键大量冲突 遍历一致性
1.7 分段锁 查找慢 易被锁阻塞
1.8 CAS+树 稳定O(logn) 比较优秀

简单一句话:1.7 读写分段锁,跑满高速路还堵车;1.8 脱胎换骨,红绿灯智能变道,加点"算法调度",体验大变脸!


经验启示

  • 多线程首选 1.8 及以上,不用 segment 锁省心
  • Async 大量写入/高冲突 key,红黑树才是真香代码
  • 不想卡链表查找?JDK 1.8 后不怕碰撞怪兽
  • 想偷懒?1.8 遍历、并发用法更随心,不用操心锁分段

唉,老了,偶尔还是怀念 Segment 那点"老锁情怀",但终究得向先进技术低头。也许代码本来也是进化史------每一版改动后,费神琢磨"为啥这样",也就有了新技能傍身。大家有啥并发"笑话",咱评论区扯一扯呗?

写到这儿,键盘都热了,今天就聊到这儿吧。忙到凌晨的程序员,才能继续踩下一个坑不是?

相关推荐
xcl09251 小时前
幼儿托育系统开发实战:从需求分析到上线全流程指南
java·大数据·需求分析
吴声子夜歌2 小时前
ApacheCommons——commons-cli(命令行参数解析)
java·开发语言·apache
小小猪的春天2 小时前
Java 手写第一个 MCP Server:Spring AI MCP 半小时跑通
java·人工智能·spring boot·ai编程
find1star2 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
今天AI了吗2 小时前
DeepSeek Harness 深度解析:从评测架构到实战落地
java·网络·数据库·人工智能·架构·java-ee
许彰午3 小时前
27-AuthService登录链路
java·低代码·架构
泡海椒3 小时前
JQuick-Curl 性能分析:并发场景下的性能表现与调优,第三方接口调用不只要快写也要稳跑
java·开发语言·okhttp
Rain的Java大神之路4 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
自动化监测Learner4 小时前
Navicat Premium 17 中文版安装教程(2026最新版)
java·linux·数据库
那个松鼠很眼熟w4 小时前
4.Spring-Ai入门案例
java·人工智能·spring