💡 核心结论:一句话先记住

老版本(JDK 1.7)的“分段锁”就像把一个大仓库死板地隔成 16 个小隔间,不管仓库后续扩容多大,永远只有 16 把锁,人多了还是卡。

新版本(JDK 1.8)彻底废弃了这种做法,直接升级为 “CAS + synchronized(按位置精准加锁)”。现在是仓库有多少个格子,就有多少把锁,不仅锁的粒度更细,而且省内存、速度还飞快!


🛑 老版本“分段锁”的三大硬伤(为什么要换?)

1. 并发度是死的,无法随容量长大

老版本的分段锁(Segment)数量在刚创建时就固定了(默认 16 个)。 这意味着,哪怕后面数据量暴增,数组扩容到了 6 万多个格子,锁却依然只有 16 把。结果就是一个 Segment 锁要同时管几千个格子,多线程一多,大家还是得老老实实排队,并发性能直接遇到天花板。

2. 占内存,公摊面积大

每个 Segment 独立小隔间都是一个完整的“小 HashMap”,里面有自己独立的数组、计数器和锁状态。这些中间件非常消耗内存空间,相当于买房子送了一堆没用的公摊面积。

3. 办事效率低,要对两次暗号

存取一个数据,程序得先哈希定位它在哪个 Segment(小隔间),然后再哈希定位在隔间里的哪个桶(格子)。连续做两次 Hash 计算,代码复杂还浪费 CPU 算力。


✨ 新版本“CAS + synchronized”的四大优势

JDK 1.8 直接把中间的 Segment 隔间全部拆掉,变成了单层直达结构(直接操作 Node 数组),带来了质的飞跃:

  • 锁粒度细到极致: 实现了“桶级锁”。你用你的 1 号格子,我用我的 2 号格子,咱们互不干扰。
  • 并发度随容量一起涨: 数组扩容有多少个格子,并发度就有多高,理论上没有上限!
  • 内存更省: 砍掉了 Segment 中间层,省下了大把的系统内存。
  • 读数据完全无锁: 配合 volatile(千里眼)黑科技,读数据(get)完全不需要加锁,直接看,效率拉满。

🧠 面试高频追问:为什么用 synchronized,而不是 ReentrantLock?

很多人奇怪,以前大家都嫌弃 synchronized 笨重,为什么 1.8 反而用它了?

  1. 底层优化了: 自从 JDK 1.6 之后,官方对 synchronized 进行了疯狂的“锁升级”优化(引入了偏向锁、轻量级锁)。在没有激烈竞争时,它的性能和 CAS 一样快,早就不是当年的“大铁锁”了。
  2. 极省内存: 如果用 ReentrantLock,6 万个格子就需要单独创建 6 万个锁对象,内存直接爆掉。而 synchronized 直接利用内部现有的常规节点(桶头对象)当锁,不需要额外创建任何锁对象,零内存开销!
  3. 安全省心: synchronized 代码执行完或者出异常时会自动释放锁,不像 ReentrantLock 还得手动写 unlock(),一不小心忘了释放就会导致线上死锁大事故。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐