Disruptor单机最强队列

介绍

Disruptor拥有开飞机般的速度,单线程里每秒处理600w订单,业务逻辑处理器完全是运行在内存中的,是基于事件源驱动的。

Maven包

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.2</version>
</dependency>

Disruptor的特点

对比ConcurrentLinkedQueue : 链表实现
JDK中没有ConcurrentArrayQueue
Disruptor是数组实现的
无锁,高并发,使用环形Buffer,直接覆盖(不用清除)旧的数据,降低GC频率
实现了基于事件的生产者消费者模式(观察者模式)

RingBuffer

环形队列
RingBuffer的序号,指向下一个可用的元素
采用数组实现,没有首尾指针
对比ConcurrentLinkedQueue,用数组实现的速度更快,数组遍历更快

环形数组,直接覆盖
当Buffer被填满的时候到底是覆盖还是等待,由Producer决定
长度是2的n次幂

Disruptor开发步骤

定义Event - 队列中需要处理的元素
定义Event工厂,用于填充队列
这里牵扯到效率问题:disruptor初始化的时候,会调用Event工厂,对ringBuffer进行内存的提前分配
GC产频率会降低
定义EventHandler(消费者),处理容器中的元素

ProducerType生产者线程模式

ProducerType有两种模式 Producer.MULTI和Producer.SINGLE
默认是MULTI,表示在多线程模式下产生sequence
如果确认是单线程生产者,那么可以指定SINGLE,效率会提升
如果是多个生产者(多线程),但模式指定为SINGLE,会出什么问题呢?

等待策略

1,(常用)BlockingWaitStrategy:通过线程阻塞的方式,等待生产者唤醒,被唤醒后,再循环检查依赖的sequence是否已经消费。
2,BusySpinWaitStrategy:线程一直自旋等待,可能比较耗cpu
3,LiteBlockingWaitStrategy:线程阻塞等待生产者唤醒,与BlockingWaitStrategy相比,区别在signalNeeded.getAndSet,如果两个线程同时访问一个访问waitfor,一个访问signalAll时,可以减少lock加锁次数.
4,LiteTimeoutBlockingWaitStrategy:与LiteBlockingWaitStrategy相比,设置了阻塞时间,超过时间后抛异常。
5,PhasedBackoffWaitStrategy:根据时间参数和传入的等待策略来决定使用哪种等待策略
6,TimeoutBlockingWaitStrategy:相对于BlockingWaitStrategy来说,设置了等待时间,超过后抛异常
7,(常用)YieldingWaitStrategy:尝试100次,然后Thread.yield()让出cpu
(常用)SleepingWaitStrategy : sleep
消费者异常处理
默认:disruptor.setDefaultExceptionHandler()
覆盖:disruptor.handleExceptionFor().with()

/**
 *  定义事件
 *   事件(Event)是通过disruptor进行交换的数据类型
 */
public class LongEvent {
    private long value;
    public void set(long value){
        this.value=value;
    }
}
/**
 *  定义事件工厂
 *  在RingBuffer上预创建Event实例
 */
public class LongEventFactory implements EventFactory<LongEvent> {
    @Override
    public LongEvent newInstance() {
        return new LongEvent();
    }
}
/**
 * 定义事件处理的具体实现
 */
public class LongEventHandler implements EventHandler<LongEvent> {
    @Override
    public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {
        System.out.println("Event:" + event);
    }
}
public class LongEventProducer {
    private final RingBuffer<LongEvent> ringBuffer;
    public LongEventProducer(RingBuffer<LongEvent> ringBuffer){
        this.ringBuffer=ringBuffer;
    }

    /**
     *  onData用来发布事件,没调用一次就发布一次
     *  他的参数会用过事件传递给消费者
     */
    public void onData(ByteBuffer bb){
        //找到下一个事件槽
        long sequence=ringBuffer.next();
        try {
            // 获取盖序列化对应的事件
            LongEvent event=ringBuffer.get(sequence);
            //获取要通过事件传递的业务数据
            event.set(bb.getLong(0));
        }finally {
            //发布事件
            ringBuffer.publish(sequence);
        }
    }
}
public class LongEventMain {
    public static void main(String[] args) {
        //创建缓冲池
        ExecutorService executor= Executors.newCachedThreadPool();
        //创建工厂
        LongEventFactory factory=new LongEventFactory();
        //创建bugffersize  也就是RingBuffer的大小,必须是2的N次方
        int ringBufferSize=1024*1024;


        //创建disruptor
        Disruptor<LongEvent> disruptor=new Disruptor<LongEvent>(factory,ringBufferSize,executor, ProducerType.SINGLE,new YieldingWaitStrategy());

        //连接消费事件的方法
        disruptor.handleEventsWith(new LongEventHandler());

        //启动
        disruptor.start();
        //Disruptor发布事件是一个两段提交的过程
        //发布事件
        RingBuffer<LongEvent> ringBuffer=disruptor.getRingBuffer();
        LongEventProducer producer=new LongEventProducer(ringBuffer);

        ByteBuffer byteBuffer=ByteBuffer.allocate(8);
        for (long l=0;l<100;l++){
            byteBuffer.putLong(0,1);
            producer.onData(byteBuffer);
        }

        disruptor.shutdown();//关闭disruptor,方法会阻塞,知道所有的事件都得到处理
        executor.shutdown();//关闭线程池,如果需要的话,必须手动关闭,
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值