disruptor通过序列号+cas+ringbuffer消除锁竞争,使线程无需等待即可协作,彻底避免blocked状态。其预分配内存、无锁协作、内存屏障和缓存行对齐等设计,从根源上规避了传统阻塞队列引发的线程挂起与上下文切换问题。

因为 BLOCKED 状态本质是线程在争抢锁时被挂起,而 Disruptor 用序列号+CAS+RingBuffer 把锁彻底拿掉了——不等锁,自然就不会 BLOCKED。
BLOCKED 状态是怎么来的
Java 线程进入 BLOCKED,几乎都源于对共享资源的同步访问:比如往 ArrayBlockingQueue 里 put 一个事件,发现队列满了,就只能 wait();或者多个线程同时调用 LinkedBlockingQueue 的 offer(),内部 ReentrantLock 就会触发线程排队。一旦并发量上来,线程不是在运行,就是在等锁、被挂起、被唤醒——上下文切换飙升,CPU 大量空转。
网关作为流量入口,每个请求解析、路由、鉴权、日志都要过队列中转。传统队列一卡,整个线程池就淤积,线程状态大面积变 BLOCKED,吞吐断崖下跌。
Disruptor 是怎么“消灭” BLOCKED 的
- 环形缓冲区预分配:所有 Event 对象在启动时就创建好、放进固定大小的数组里,全程无 new、无 GC 压力,也无需运行时加锁扩容
- 序列号驱动协作:生产者通过 CAS 申请下一个可用序号(如从 1001 → 1002),写入对应槽位后发布;消费者只读自己已知的序号范围,不查、不等、不锁
- 内存屏障保可见性:不用 volatile 或 synchronized,靠 Unsafe.storeFence / loadFence 保证写入数据对消费者立即可见,避免了锁带来的阻塞语义
- 缓存行对齐防伪共享:Sequence、RingBuffer 的关键字段都做了 @Contended 或手动 padding,确保不同线程修改的变量不在同一 CPU 缓存行,消除无效缓存失效
为什么这是高级架构师的标配动作
不是因为用了 Disruptor 就高级,而是因为选它意味着你真正盯住了线程状态这个底层信号:
- 看到线程 dump 里大量 BLOCKED,第一反应不是加机器或调线程池,而是问“哪个环节还在用阻塞队列”
- 清楚知道网关里最耗时的不是业务逻辑,而是同步日志、跨线程事件投递、规则匹配结果转发这些“中间态搬运”
- 愿意为 10% 的延迟下降,接受更陡的学习曲线和更细的配置控制(比如 WaitStrategy 选 Sleeping 还是 BusySpin)
- 能把 RingBuffer 大小、批次消费数量、消费者依赖链这些参数,和实际 QPS、P99 延迟、GC pause 关联起来调优
落地时容易踩的坑
Disruptor 不是开箱即用的“性能银弹”,用错反而更慢:
- RingBuffer 太小 → 频繁覆盖未消费事件 → 数据丢失;太大 → 内存浪费 + 缓存局部性下降
- WaitStrategy 选错:默认 BlockingWaitStrategy 本质还是锁,高并发下又回到原点;BusySpin 虽快但吃满 CPU,需搭配核心数与负载节奏评估
- EventHandler 里做耗时操作(如远程 HTTP 调用、DB 查询)→ 卡住整个消费者线程 → 吞吐归零;必须拆出异步线程池处理
- 多消费者间有依赖却没配 SequenceBarrier → 顺序错乱,比如“鉴权完成”事件跑到“路由匹配”之前











