Disruptor—1.原理和使用简介

大纲

1.Disruptor简介

2.Disruptor和BlockingQueue的压测对比

3.Disruptor的编程模型

4.Disruptor的数据结构与生产消费模型

5.RingBuffer + Disruptor + Sequence相关类

6.Disruptor的WaitStrategy消费者等待策略

7.EventProcessor + EventHandler等类

8.Disruptor的运行原理图

9.复杂业务需求下的编码方案和框架

10.Disruptor的串行操作

11.Disruptor的并行操作

12.Disruptor的多边形操作

13.Disruptor的多生产者和多消费者

1.Disruptor简介

(1)Disruptor是什么

(2)Disruptor的特点

(3)Disruptor的核心

(1)Disruptor是什么

Martin Fowler在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,能够以很低的延迟产生大量的交易。LMAX是建立在JVM平台上,其核心是一个业务逻辑处理器,能够在一个线程里每秒处理6百万订单。LMAX业务逻辑处理器完全是运行在内存中,使用事件驱动方式,其核心是Disruptor。

(2)Disruptor的特点

大大简化了并发程序开发的难度,性能上比Java提供的一些并发包还好。

Disruptor是一个高性能异步处理框架,实现了观察者模式。Disruptor是无锁的、是CPU友好的。Disruptor不会清除缓存中的数据,只会覆盖缓存中的数据,不需要进行垃圾回收。Disruptor业务逻辑是纯内存操作,使用事件驱动方式。

(3)Disruptor的核心

Disruptor核心是一个RingBuffer,RingBuffer是一个数组,没有首尾指针。RingBuffer是一个首尾相接的环,用于在不同线程之间传递数据。

如果RingBuffer满了,是继续覆盖还是等待消费,由生产者和消费者决定。假设RingBuffer满了,生产者有两个选择:选择一是等待RingBuffer有空位再填充,选择二是直接覆盖。同时消费者也有两种选择:选择一是等待RingBuffer满了再消费,选择二是RingBuffer填充一个就消费一个。

RingBuffer有一个序号Sequence,这个序号指向数组中下一个可用元素。随着数据不断地填充这个数组,这个序号会一直增长,直到绕过这个环。序号指向的元素,可以通过mod计算:序号 % 长度 = 索引。建议将长度设为2的n次方,有利于二进制计算:序号 & (长度 - 1) = 索引。

Sequence通过顺序递增的序号来进行编号,以此管理正在进行交换的数据(事件)。对数据处理的过程总是沿着需要逐个递增处理,从而实现线程安全。一个Sequence用于跟踪标识某个特定的事件处理者的处理进度。

2.Disruptor和BlockingQueue的压测对比

Disruptor的性能是ArrayBlockingQueue的3倍+,这里的测试代码都是基于单线程的单生产者单消费者模式运行的。但是Disruptor本身就支持多生产者多消费者模型,测试中使用单线程明显降低了其性能。而ArrayBlockingQueue在多生产者多消费者场景下,其性能又会比单生产者单消费者场景下更低。因此,在实际应用中,Disruptor的性能会是ArrayBlockingQueue的3倍+。

public interface Constants {
    int EVENT_NUM_OHM = 100000000;
    int EVENT_NUM_FM = 50000000;
    int EVENT_NUM_OM = 10000000;
}

public class ArrayBlockingQueue4Test {
    public static void main(String[] args) {
        //初始化一个大小为100000000的有界队列ArrayBlockingQueue,为了避免在测试时由于扩容影响性能,所以一开始就初始化大小为1亿
        final ArrayBlockingQueue<Data> queue = new ArrayBlockingQueue<Data>(100000000);
        //开始时间
        final long startTime = System.currentTimeMillis();
        //向容器中添加元素
        new Thread(new Runnable() {
            public void run() {
                long i = 0;
                //首先把数据投递到有界队列ArrayBlockingQueue,单线程的生产者
                while (i < Constants.EVENT_NUM_OHM) {
                    Data data = new Data(i, "c" + i);
                    try {
                        queue.put(data);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                }
            }
        }).start();
  
        //从容器中取出元素
        new Thread(new Runnable() {
            public void run() {
                int k = 0;
                //然后才开始消费有界队列中的数据,单线程的消费者
                while (k < Constants.EVENT_NUM_OHM) {
                    try {
                        queue.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    k++;
                }
                //结束时间
                long endTime = System.currentTimeMillis();
                //整个main函数就是单线程运行,处理1千万数据,大概耗时3.6秒
                System.out.println("ArrayBlockingQueue costTime = " + (endTime - startTime) + "ms");
            }
        }).start();
    }
}

public class DisruptorSingle4Test {
    public static void main(String[] args) {
        int ringBufferSize = 65536;
        final Disruptor<Data> disruptor = new Disruptor<Data>(
            new EventFactory<Data>() {
                public Data newInstance() {
                    return new Data();
                }
            },
            ringBufferSize,
            //设置为单线程运行
            Executors.newSingleThreadExecutor(),
            //单生产者模式
            ProducerType.SINGLE,
            //new BlockingWaitStrategy()
            new YieldingWaitStrategy()
        );
  
        //创建一个消费者事件处理器
        DataConsumer consumer = new DataConsumer();
        //消费数据
        disruptor.handleEventsWith(consumer);
        disruptor.start();
  
        //单线程的消费者
        new Thread(new Runnable() {
            public void run() {
                RingBuffer<Data> ringBuffer = disruptor.getRingBuffer();
                for (long i = 0; i < Constants.EVENT_NUM_OHM; i++) {
                    long seq = ringBuffer.next();
                    Data data = ringBuffer.get(seq);
                    data.setId(i);
                    data.setName("c" + i);
                    //发布一个数据被消费的事件
                    ringBuffer.publish(seq);
                }
            }
        }).start();
    }
}

public class DataConsumer implements EventHandler<Data> {
    private long startTime;
    private int i;
    
    public DataConsumer() {
        this.startTime = System.currentTimeMillis();
    }
    
    public void onEvent(Data data, long seq, boolean bool) throws Exception {
        i++;
        if (i == Constants.EVENT_NUM_OHM) {
            long endTime = System.currentTimeMillis();
            //处理1千万的数据,大概耗时1.1秒
            System.out.println("Disruptor costTime = " + (endTime - startTime) + "ms");
            //可见Disruptor的性能是ArrayBlockingQueue的3倍+
        }
    }
}

3.Disruptor的编程模型

(1)Disruptor的使用步骤

(2)Disruptor的使用演示

(1)Disruptor的使用步骤

步骤一:建立一个Event工厂类,用于创建数据(Event类实例对象)
步骤二:建立一个监听事件类(Event处理器),用于处理数据(Event类实例对象)
步骤三:创建Disruptor实例,配置一系列参数
步骤四:编写生产者组件,向Disruptor容器投递数据

(2)Disruptor的使用演示

一.引入pom依赖

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

二.建立Event工厂类用于创建数据

Event工厂类创建的数据就是Event类实例对象。

public class OrderEvent {
    //订单的价格
    private long value;
    
    public long getValue() {
        return value;
    }
    
    public void setValue(long value) {
        this.value = value;
    }
}

public class OrderEventFactory implements EventFactory<OrderEvent> {
    //返回一个空的数据对象(OrderEvent对象实例)
    public OrderEvent newInstance() {
        return new OrderEvent();
    }
}

三.建立监听事件类用于处理数据

监听事件类就是Event处理器,处理的数据就是Event类实例对象

public class OrderEventHandler implements EventHandler<OrderEvent> {
    public void onEvent(OrderEvent event, long sequence, boolean endOfBatch) throws Exception {
        Thread.sleep(1000);
        System.err.println("消费者: " + event.getValue());
    }
}

四.创建Disruptor对象实例

public class Main {
    public static void main(String[] args) {
        //参数准备
        OrderEventFactory orderEventFactory = new OrderEventFactory();
        int ringBufferSize = 4;
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
  
        //参数一:eventFactory,消息(Event)工厂对象
     
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值