一、为什么需要 Disruptor?—— 背景与问题
在高并发编程中,传统的队列(如 java.util.concurrent.ArrayBlockingQueue 或 LinkedBlockingQueue)在高性能场景下会成为瓶颈,主要问题在于:
- 锁竞争:生产者和消费者之间使用同一把锁(或读写锁),导致线程频繁挂起、唤醒,上下文切换开销巨大。
- 伪共享:多个线程修改的、逻辑上独立但物理上相邻的变量,会因 CPU 缓存行的同步而导致性能急剧下降。
- 内存分配开销:对于链表结构的队列,每次入队出队都可能涉及节点对象的创建和垃圾回收,在高吞吐下 GC 压力大。
- 低效的遍历:队列的'头出尾入'设计,使得遍历和批量操作不够高效。
Disruptor 的目标就是解决这些问题,实现极低延迟、超高吞吐的线程间数据交换。
二、核心设计思想
Disruptor 不是一个传统意义上的 FIFO 队列,而是一个基于数组的环形缓冲区(Ring Buffer)。它的核心设计思想可以概括为以下几点:
1. 环形数组结构

- 使用一个固定大小的数组预先分配所有内存,避免运行时动态内存分配。
- 数组元素(
Event)在初始化时就全部创建好,并被重复使用。这消除了 GC 压力。 - 通过取模运算(实际是高效的位运算,要求数组大小为 2 的幂次)实现环形覆盖,指针无限递增,永不回收。
2. 无锁设计
- 核心操作(生产与消费)完全无锁(Lock-Free),通过内存屏障(Memory Barrier) 和 CAS(Compare-And-Swap) 操作实现线程安全。
- 生产者之间通过 CAS 竞争下一个可写的槽位。
- 生产者和消费者之间通过序列(Sequence) 的协调来工作,消费者通过等待策略(Wait Strategy) 来感知新数据的到来。
3. 消除伪共享(Cache Line Padding)
- 识别出会被多个线程频繁写入的关键变量(如生产者的
cursor,各个消费者的Sequence)。 - 通过在这些变量前后添加无意义的填充字节(
padding),确保每个核心变量独占一个完整的 CPU 缓存行(通常为 64 字节),防止它们被意外地加载到同一个缓存行中,从而避免一个线程的写入使另一个线程的整个缓存行失效。
4. 批量与依赖关系
- 支持批量处理事件,能极大提高吞吐量。
- 可以显式地构建消费者之间的依赖关系图(如
A->B->C或A,B 都完成 -> C),实现高效的工作流。
三、核心组件与原理
1. 环形缓冲区(Ring Buffer)
这是 Disruptor 的物理存储核心。它是一个固定大小的 Object[] 数组。每个位置被称为一个'槽'(slot)。
size:必须是 2 的幂次(如 1024)。这样sequence % size可以通过sequence & (size - 1)位运算高效完成。cursor:生产者发布事件的序列号。它代表最后成功发布的事件的位置。这是一个 对象。


