Skip to content
困难

一句话答案

不同核心修改同一缓存行(64B)中不同变量导致频繁失效,解决:@Contended 注解或手动填充使变量独占缓存行。

核心要点

CPU 缓存行(Cache Line):

  • CPU 读取内存的最小单位是缓存行(通常 64 字节)
  • 一次加载会把相邻数据一起加入缓存

伪共享问题:

Cache Line (64 bytes): [varA | varB | padding...]
                        ↑         ↑
                     Thread1    Thread2
  • Thread1 修改 varA → 整行失效 → Thread2 的 varB 缓存也失效
  • Thread2 修改 varB → 整行失效 → Thread1 的 varA 缓存也失效
  • 结果:频繁缓存失效,性能骤降

解决方案:

  1. @Contended 注解(JDK8+):自动填充128字节
    java
    @sun.misc.Contended
    class PaddedAtomicLong extends AtomicLong {}
    需要 -XX:-RestrictContended
  2. 手动填充:在变量前后加 long 字段填满一行
  3. Disruptor RingBuffer 的 Sequence 就用了填充避免伪共享
追问与易错

追问方向:

  • 怎么验证伪共享存在?
  • Java 中还有哪些组件用了缓存行填充?
  • @Contended 需要什么 JVM 参数?

易错点:

  • ❌ 伪共享很少发生——高并发计数器场景很常见
  • ❌ 手动填充比 @Contended 好——后者更可靠

💡 记忆锚点

CPU 读内存像吃自助餐用托盘端菜(缓存行 64 字节一次端一盘)。伪共享就是两个人的菜放在同一个盘子里——你夹了一筷子我的盘子也得重端,来回端盘子把性能吃没了。解决办法:用填充物把两人的菜隔到不同盘子里(@Contended 或手动 padding)。