题目:如何借鉴 Disruptor 的 RingBuffer 思想设计一个低延迟的无锁并发队列?
难度:high
标签:java/juc, java/concurrency, general/knowledge
评分:⭐⭐☆☆☆(2/5)
通过环形数组,来实预创建空间,通过序号实现不同索引位置的读取,使用cas不用锁来实现序号更新;去读取数组内的内容,他没有锁,使用序号可以快速读取目标位置内容实现低延迟,高内存利用,而不是像是链表读取内容还需要遍历
优点:抓住"环形数组 + 预分配 + 序号 + CAS 无锁"这四个关键点,方向对。
不足:缺了低延迟的灵魂——生产者/消费者序号协调。只说了"用序号读",没说多个生产者的序号怎么 CAS 竞争、消费者怎么通过 Sequence/SequenceBarrier 判断可消费位置、如何避免覆盖未消费数据。
补充:还有两个关键点没提——缓存行填充(padding)消除伪共享、预分配对象避免 GC;以及 Disruptor 用"批处理 + 序号依赖"做到无锁且高吞吐。
核心考点定位:能否讲清 RingBuffer 的无锁协调机制(序号)与低延迟手段(防伪共享、无 GC)。
知识点拆解:
index & (size-1);元素在启动时全部预创建,运行期不再 new,避免 GC 抖动。cursor/next 序号,多生产者用 getAndIncrement 抢占槽位SequenceBarrier 等待"可消费序号",用 min(生产者序号, 依赖序号) 决定能消费到哪考察方向:
ArrayBlockingQueue(锁)、ConcurrentLinkedQueue(无界 CAS 链表)对比延伸递进面试题:
Sequencerindex & (n-1) 位运算代替取模,更快【一句话结论】
面试官您好,RingBuffer 的核心是"环形数组 + 序号协调 + 无锁",本质是用序号代替锁来协调生产消费。
【三点展开】
第一,空间预分配:容量取 2 的幂,启动时把元素全部创建好,取模用位运算,运行期零 GC;
第二,序号协调是无锁的关键:生产者用 CAS 抢占写序号,消费者用 SequenceBarrier 按依赖等待可读序号,靠"序号差 ≥ 容量"判断能否覆盖;
第三,低延迟的细节:序号字段做缓存行填充消除伪共享,再靠批处理一次取连续区间,减少 CAS 和等待。
【一句边界】
当然,Disruptor 适合吞吐极高、依赖简单的场景;如果只是普通异步解耦,BlockingQueue 更简单够用。