发布于2026-07-08 阅读(0)
扫一扫,手机访问
先说几个核心判断:伪共享这玩意儿,还真不是你代码写错了,而是多线程在底层被硬件“坑”了一把。当多个 CPU 核心上的线程,各自修改同一缓存行里不同变量时,MESI 协议就得反复做一致性协调——你改一下,我失效一次;我再改一下,你又失效一次。一来二去,性能直接崩掉。而 @Contended 注解干的事很简单:告诉 JVM 在字段前后塞一堆填充字节,把它跟旁边字段彻底隔开,独占整个缓存行。

CPU 读写内存,不是按字节来的,而是以缓存行为单位——主流是 64 字节。当两个线程分别更新同一缓存行上的 valueA 和 valueB 时,好戏就上演了:
这么一来一回,就成了高频“拉锯战”。结果很统一:吞吐量掉到原来的 1/5 到 1/2,CPU 跑满、但 jstack 抓不到锁、日志里也看不到任何异常。这才是最让人头疼的地方——没有直接错误,只有性能烂。
它的思路很简单:不动逻辑,只动手脚。在被标记字段的前后各插一段填充(padding),把字段“包”成一个孤岛,保证它前后至少空出一个缓存行的距离。
-XX:ContendedPaddingWidth=64 可以显式设为标准缓存行大小@Contended("counter") 能让同组字段打包后再整体填充。比如 head 和 tail 这两个本就需要共处一组的变量,可以放在一起隔离,但又不会和外部字段互相干扰这就有意思了——你不只可以隔离单个字段,还能按业务逻辑把热点字段分到同一组里,内部共享、外部隔离。
需要特别警惕的是,@Contended 是“有条件启用”的特性,缺一个参数它就不干活:
-XX:+UnlockExperimentalVMOptions(JDK 8/9 必须开启,否则直接忽略)-XX:+UseContended(JDK 8) 或 -XX:-RestrictContended(JDK 9+)另外还有几个隐性规则:静态字段加了也白加;public 字段会被 JVM 直接无视;必须是实例字段,且访问权限为 private/protected 或包级。这几个坑踩的人不少,记得检查到位。
如果环境不支持注解,或者你更想掌控一切,手动填充也是个靠谱的选择,兼容性反而更好:
long p1, p2, p3, p4, p5, p6, p7;ClassLayout.parseClass(YourClass.class).toPrintable(),可以直观看到字段真实偏移说到底,理解伪共享不是为了炫技,而是让你在排查性能问题时多一个方向——下次遇到 CPU 高、锁不明显的场景,不妨先看看缓存行上是不是正打着一场“看不见的战争”。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8