总线加锁机制和 MESI 缓存一致性协议¶
一、问题¶
多核 CPU 每个核有自己的缓存,同一个变量可能在多个核的缓存里都有副本。如果核 A 修改了,核 B 的缓存还是旧值,怎么办?
二、总线加锁(最早的方案)¶
CPU 通过锁总线来保证同一时刻只有一个核访问内存:
执行时 CPU 锁死系统总线,其他核不能通过总线访问内存。
缺点¶
- 性能极差:锁总线期间所有核都不能访问内存。
- 粗粒度:一个核改一个字节,整个内存都不能访问。
三、MESI 协议¶
现代 CPU 用 MESI 缓存一致性协议,按缓存行为单位管理状态:
| 状态 | 含义 |
|---|---|
| M Modified | 当前核修改过,与内存不一致,独占 |
| E Exclusive | 缓存行独占,和内存一致 |
| S Shared | 多个核都有,和内存一致 |
| I Invalid | 无效,需要重新从内存读 |
四、状态转换¶
读操作¶
- 本地缓存命中(M/E/S):直接用。
- 未命中:发广播,其他核如果有 M 状态的缓存行,先写回内存。
- 其他核都没有:变 E;其他核有:变 S。
写操作¶
- 当前是 E 或 M:直接写,变 M。
- 当前是 S:发无效化请求给其他核,它们变 I,自己变 M。
- 当前是 I:先获得独占权(发广播),再写。
五、为什么用 MESI 而不是总线锁¶
- 只锁一个缓存行,不是整个总线。
- 多核可以同时读(S 状态),不冲突。
- 写时才做协调。
六、和 Java 的关系¶
volatile写后插入的lock指令,本质就是让缓存行回到 M/E 状态并刷回内存。- MESI 是硬件层的一致性,Java 内存模型(JMM)在此基础上定义了更高层的可见性语义。
高频追问
- MESI 为什么叫这四个字母?Modified / Exclusive / Shared / Invalid。
- S 状态为什么性能好?多核同时读不用协调。