volatile 在 disruptor 的 sequence 类中核心作用是保障 long value 的可见性,确保一个线程的修改能被其他线程及时准确看到;它不提供原子性或互斥,而是与 cas 协同实现无锁进度跟踪,并为缓存行填充防止伪共享奠定基础。

volatile 在 Disruptor 的 Sequence 类中,核心作用是保障序号(long value)在多线程环境下的**可见性**,而非原子性或互斥控制。它不负责解决“多个线程同时写”的竞态问题——那由 CAS 操作承担;它只确保一个线程对 value 的修改,能被其他线程及时、准确地看到。
为什么 Sequence 必须用 volatile 修饰 value
Disruptor 中每个 Sequence 实例代表一个游标(如生产者位置、消费者进度),多个线程(如不同 EventHandler 或生产者线程)会频繁读取该值来判断是否可读/可写。若不用 volatile:
- CPU 可能将 value 缓存在寄存器或私有 L1/L2 缓存中,不主动刷回主内存;
- 其他线程读到的仍是旧值,导致“假空闲”或“假阻塞”,例如消费者误判数据未就绪而空转等待;
- JVM 编译器可能重排序读写指令,破坏事件发布与游标更新之间的 happens-before 关系。
volatile 如何配合 CAS 构成无锁推进机制
Sequence 的典型操作模式是“先读后 CAS 更新”,volatile 为这一模式提供基础保障:
-
读取时:调用
get()方法直接读 volatile long value,强制从主内存(或最新缓存行)加载,避免脏读; -
更新时:调用
compareAndSet(expected, next),底层使用 CPU 的 cmpxchg 指令——它本身具有内存屏障语义,能保证写入立即对其他核可见; - 协同效果:volatile 保证读的实时性,CAS 保证写的原子性与可见性,二者结合使 Sequence 成为轻量、可靠、无锁的进度跟踪单元。
它不解决伪共享,但为伪共享优化打下基础
虽然 volatile 本身不能防止伪共享(False Sharing),但它是 Disruptor 进行缓存行填充(Cache Line Padding)的前提:
- Sequence 类通过继承
LhsPadding和RhsPadding,在 volatile value 前后填充 7 个 long 字段,确保 value 独占一个 64 字节缓存行; - 若 value 不是 volatile,即使加了填充,JVM 也无法保证对该字段的访问触发缓存同步行为;
- 只有 volatile + 填充,才能真正隔离不同 Sequence 实例间的缓存行干扰,避免因同一缓存行被多核反复失效而拖慢性能。
和普通变量相比,volatile 在 RingBuffer 场景中的实际影响
在 RingBuffer 的单生产者或多生产者模型中,volatile 使以下关键路径保持正确性:
- 生产者调用
next()后,必须让所有消费者立即看到新游标,否则无法触发事件分发; - 多个消费者各自维护独立 Sequence,它们需持续读取生产者 Sequence 和彼此的 Sequence(通过 Sequencer 获取最小消费位置),volatile 是这些跨线程读操作可信的基石;
- WaitStrategy(如 BusySpinWaitStrategy)依赖对 Sequence 的高频轮询,volatile 是低延迟响应的必要条件。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











