外观
一句话答案
不同核心修改同一缓存行(64B)中不同变量导致频繁失效,解决:@Contended 注解或手动填充使变量独占缓存行。
核心要点
CPU 缓存行(Cache Line):
- CPU 读取内存的最小单位是缓存行(通常 64 字节)
- 一次加载会把相邻数据一起加入缓存
伪共享问题:
Cache Line (64 bytes): [varA | varB | padding...]
↑ ↑
Thread1 Thread2- Thread1 修改 varA → 整行失效 → Thread2 的 varB 缓存也失效
- Thread2 修改 varB → 整行失效 → Thread1 的 varA 缓存也失效
- 结果:频繁缓存失效,性能骤降
解决方案:
- @Contended 注解(JDK8+):自动填充128字节java需要
@sun.misc.Contended class PaddedAtomicLong extends AtomicLong {}-XX:-RestrictContended - 手动填充:在变量前后加 long 字段填满一行
- Disruptor RingBuffer 的
Sequence就用了填充避免伪共享
追问与易错
追问方向:
- 怎么验证伪共享存在?
- Java 中还有哪些组件用了缓存行填充?
- @Contended 需要什么 JVM 参数?
易错点:
- ❌ 伪共享很少发生——高并发计数器场景很常见
- ❌ 手动填充比 @Contended 好——后者更可靠
💡 记忆锚点
CPU 读内存像吃自助餐用托盘端菜(缓存行 64 字节一次端一盘)。伪共享就是两个人的菜放在同一个盘子里——你夹了一筷子我的盘子也得重端,来回端盘子把性能吃没了。解决办法:用填充物把两人的菜隔到不同盘子里(@Contended 或手动 padding)。