Disruptor
介绍
其实是来源于一个算法,解决高并发下队列锁的问题,完全运行在内存中
-
相对于java的队列,它是一个无锁的有界队列
-
LMAX Disruptor是一个高性能的线程间消息传递库。
-
Disruptor是一个高性能的异步处理框架
-
目前最快的消息框架(轻量的JMS),也可以认为是一个观察者模式的实现,或者事件监听模式的实现。
-
一种高效的"生产者-消费者"模型
使用场景
- PCP(生产者-消费者问题)
实战
-
new Event类 , 其实是用来包装数据(事件)的
-
EventFactory ,newInstance()
-
消费者:new EventHandler()
-
ThreadFactory线程工厂
-
new Disruptor
( EventFactory,
ringbuffersize,(环形数组大小,2的N次方)
threadFactory,
ProducerType enum(是否多个生产者),
WaitStrategy :等待策略类 )
- Disruptor的入口
- 封装了RingBuffer ,消费者集合引用(ConsumerRepository)
-
存储核心:RingBuffer 环行数组,通过Disruptor实例拿到它,它是Disruptor类中的一个数组
- RingBuffer 内部有一个序列生成器接口(Sequencer)
-
消费者注册监听 Disruptor.handleEventWith(handler)
- 实现 onEvent()
-
disruptor.start();
-
Disruptor.getRingBuffer();
-
new Producer(ringBuffer) ; producer.onData(ringBuffer);//ringBuffer表示容器
//producer //构造初始化RingBuffer容器 public MyEventProducer(RingBuffer<MyEvent> ringBuffer){ this.ringBuffer = ringBuffer; } try{ //1.获取下一个序号 long sequence = ringBuffer.next(); //2.从容器中取出空的事件队列 myEvent = ringBuffer.get(sequence); //3.生产数据 myEvent.setxxx(data); }finally{ //4.发布事件 ringBuffer.publish(sequence); }
核心组件
-
Sequencer 序列生成器
- 包括 单生产者,多生产者实现类。还维护了生产者和消费者序列冲突时的等待策略
-
Sequence 序列对象 组件处理的序号 引用(索引,序列) 底层实现是 AtomicLong
- 生产者和消费者都维护了各自的Sequence ,都指向了ringBuffer内的Object[]
- 这个序号是一直递增的,long是一个很大的值2的63次方-1 ,亿的平方级别的,即使是100WQPS也得用30年
- 序号的初始值是 -1
-
RingBuffer 一个首尾相接的环
-
用于上下文(线程)间传递数据的buffer
-
ringbuffer拥有一个序号Sequencer,这个序号指向数组中下一个可用元素
-
-
WaitStrategy 没有可消费的事件时,没有可生产的地方时
-
主要针对消费者线程
-
Blocking
- 性能比较低效
- 对cpu消耗小,更好的一致性
- 内部维护了一个重入锁和Condition
-
Yielding
- 性能最高
-
Sleeping
-
性能和Blocking差不多,也是一种无锁的方式
-
对生产者线程影响最小,适合用于异步日志类似的场景
-
Log4j2 就用了Disruptor这个框架
-
-
-
Event 只是一个定义,没有具体的Event类
-
Producer 只是泛指调用 Disruptor 发布事件的用户代码,Disruptor 没有定义特定接口或类型需要使用者自己定义
-
Sequence Barrier
生产消费流程
- 单生产者-单消费者
- MultiProducer - MultiConsumer
- ProducerType.MULTI
- EventHandler 变成WorkHandler
- WorkPool 多消费者工作池
优缺点
- 环形数组结构
- 避免了垃圾回收,直接覆盖
- 数组对处理器的缓存机制更加友好
- 数组元素定位 (通过位运算加速定位速度)
- 序列号%数组大小 = index ,其实是通过位运算做的不是上面的取模算法
UNSAFE.getObject(entries,REF_ARRAY_BASE + ( (sequence & indexMask) << REF_ELEMENT_SHIFT)));
- 初始化了大小 2的n次方,不需要扩容
- 无锁设计
- 每个生产者或者消费者线程,会先申请可以操作的元素位置,然后直接在该位置写入或者读取数据
- 大公司实践
- 美团网 ,得到了大数据的验证
- Disruptor 是基于单JVM的无锁队列技术 ,不是分布式下的

浙公网安备 33010602011771号