使用Disruptor的几个代码演示

来源:互联网 发布:js实现气泡随机运动 编辑:程序博客网 时间:2024/05/29 02:14

原文链接:http://www.dubby.cn/detail.html?id=9052

代码地址:https://github.com/dubby1994/disruptor-demo

关于Disruptor的原理,实在是太过复杂,限于我水平有限,这里就不一一展开。如果读者有兴趣,可以去看他们的官方文档,代码库已迁移到GitHub,https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started,如果想看中文翻译,可以直接去看并发编程网,但是这个中文翻译时,版本较低,看的时候,部分术语,方法名,甚至类名都和新版的不太一致,阅读时请注意。在这里,仅仅给出几个实例代码。

1. 编码准备

1.1 版本依赖

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

1.2 Java版本

1.8

1.3 公用的一些类

定义的消息格式LongEvent.java

package cn.dubby.disruptor.wizard;/** * Created by teeyoung on 17/10/27. */public class LongEvent {    private long value;    public void set(long value) {        this.value = value;    }    public long getValue() {        return value;    }}

把输入对象翻译成消息消息对象Translator.java

package cn.dubby.disruptor.wizard;import com.lmax.disruptor.EventTranslatorOneArg;import java.nio.ByteBuffer;/** * Created by teeyoung on 17/10/27. */class Translator implements EventTranslatorOneArg<LongEvent, ByteBuffer> {    @Override    public void translateTo(LongEvent event, long sequence, ByteBuffer data) {        event.set(data.getLong(0));    }}

一个消息消费者LongEventHandler.java

package cn.dubby.disruptor.basic;import com.lmax.disruptor.EventHandler;/** * Created by teeyoung on 17/10/27. */public class LongEventHandler implements EventHandler<LongEvent> {    public void onEvent(LongEvent event, long sequence, boolean endOfBatch) {        System.out.println("Event: " + event.getValue());    }}

2. 简单示例

2.1 单生产者,单消费者

SingleProductorLongEventMain.java

package cn.dubby.disruptor.basic;import com.lmax.disruptor.BlockingWaitStrategy;import com.lmax.disruptor.RingBuffer;import com.lmax.disruptor.dsl.Disruptor;import com.lmax.disruptor.dsl.ProducerType;import java.nio.ByteBuffer;import java.util.concurrent.Executor;import java.util.concurrent.Executors;/** * Created by teeyoung on 17/10/27. */public class SingleProductorLongEventMain {    private static final Translator TRANSLATOR = new Translator();    public static void main(String[] args) throws Exception {        // Executor that will be used to construct new threads for consumers        Executor executor = Executors.newCachedThreadPool();        // Specify the size of the ring buffer, must be power of 2.        int bufferSize = 1024;        // Construct the Disruptor        Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(LongEvent::new, bufferSize, executor, ProducerType.SINGLE, new BlockingWaitStrategy());        // Connect the handler        disruptor.handleEventsWith(new LongEventHandler());        // Start the Disruptor, starts all threads running        disruptor.start();        // Get the ring buffer from the Disruptor to be used for publishing.        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();        ByteBuffer bb = ByteBuffer.allocate(8);        for (long l = 0; l < 10; l++) {            bb.putLong(0, l);            ringBuffer.publishEvent(TRANSLATOR, bb);            Thread.sleep(100);        }    }}

这里bufferSize的解释是the size of the ring buffer, must be power of 2.,也就是你所定义的ringbuffer的大小,必须是2的幂。

这里还需要注意的一个地方,那就是新版的Disruptor不建议我们使用Executor,而使用ThreadFactory代替。

可以简单的换成:

ThreadFactory threadFactory = new ThreadFactory() {    private final AtomicInteger index = new AtomicInteger(1);    @Override    public Thread newThread(Runnable r) {        return new Thread((ThreadGroup) null, r, "disruptor-thread-" + index.getAndIncrement());    }};Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(LongEvent::new, bufferSize, threadFactory, ProducerType.SINGLE, new BlockingWaitStrategy());

结果:

2.2 多生产者,单消费者

MultiProductorLongEventMain.java

package cn.dubby.disruptor.basic;import com.lmax.disruptor.BlockingWaitStrategy;import com.lmax.disruptor.RingBuffer;import com.lmax.disruptor.dsl.Disruptor;import com.lmax.disruptor.dsl.ProducerType;import java.nio.ByteBuffer;import java.util.concurrent.Executor;import java.util.concurrent.Executors;/** * Created by teeyoung on 17/10/27. */public class MultiProductorLongEventMain {    private static final Translator TRANSLATOR = new Translator();    public static void main(String[] args) throws Exception {        // Executor that will be used to construct new threads for consumers        Executor executor = Executors.newCachedThreadPool();        // Specify the size of the ring buffer, must be power of 2.        int bufferSize = 1024;        // Construct the Disruptor        Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(LongEvent::new, bufferSize, executor, ProducerType.MULTI, new BlockingWaitStrategy());        // Connect the handler        disruptor.handleEventsWith(new LongEventHandler());        // Start the Disruptor, starts all threads running        disruptor.start();        // Get the ring buffer from the Disruptor to be used for publishing.        new Thread(){            @Override            public void run() {                RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();                ByteBuffer bb = ByteBuffer.allocate(8);                for (long l = 0; l < 10; l++) {                    bb.putLong(0, l);                    ringBuffer.publishEvent(TRANSLATOR, bb);                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();        new Thread(){            @Override            public void run() {                RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();                ByteBuffer bb = ByteBuffer.allocate(8);                for (long l = 10; l < 20; l++) {                    bb.putLong(0, l);                    ringBuffer.publishEvent(TRANSLATOR, bb);                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();        new Thread(){            @Override            public void run() {                RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();                ByteBuffer bb = ByteBuffer.allocate(8);                for (long l = 20; l < 30; l++) {                    bb.putLong(0, l);                    ringBuffer.publishEvent(TRANSLATOR, bb);                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();    }}

这里使用三个线程同时生产。

结果:

3. 领域特定语言(DSL)

3.1 简单的消费者依赖关系

这张图的意思就是消费者3消费时,必须保证消费者1和消费者2已经完成对该消息的消费。举个例子,在处理实际的业务逻辑(C3)之前,需要校验数据(C1),以及将数据写入磁盘(C2)。

DisruptorWizardMain.java

package cn.dubby.disruptor.wizard;import com.lmax.disruptor.EventHandler;import com.lmax.disruptor.RingBuffer;import com.lmax.disruptor.dsl.Disruptor;import java.nio.ByteBuffer;import java.util.concurrent.Executor;import java.util.concurrent.Executors;/** * Created by teeyoung on 17/10/28. */public class DisruptorWizardMain {    private static final Translator TRANSLATOR = new Translator();    public static void main(String[] args) throws InterruptedException {        Executor executor = Executors.newCachedThreadPool();        int bufferSize = 1024;        EventHandler handler1 = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("handler1 : " + event.getValue());            }        };        EventHandler handler2 = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("handler2 : " + event.getValue());            }        };        EventHandler handler3 = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("handler3 : " + event.getValue() + " arrived. Handler1 and handler2 should have completed. Completed.\n");            }        };        Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent::new, bufferSize, executor);        disruptor.handleEventsWith(handler1, handler2).then(handler3);        disruptor.start();        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();        ByteBuffer bb = ByteBuffer.allocate(8);        for (long l = 0; true; l++) {            bb.putLong(0, l);            ringBuffer.publishEvent(TRANSLATOR, bb);            Thread.sleep(1000);        }    }}

这里主要关注disruptor.handleEventsWith(handler1, handler2).then(handler3);定义了先让1和2消费,然后才能让2消费。
运行结果:

3.1 复杂的消费者依赖关系

这张图的意思就是消费者1b消费时,必须保证消费者1a已经完成对该消息的消费;消费者2b消费时,必须保证消费者2a已经完成对该消息的消费;消费者c3消费时,必须保证消费者1b和2b已经完成对该消息的消费。

DisruptorWizardMain2.java

package cn.dubby.disruptor.wizard;import com.lmax.disruptor.EventHandler;import com.lmax.disruptor.RingBuffer;import com.lmax.disruptor.dsl.Disruptor;import java.nio.ByteBuffer;import java.util.concurrent.Executor;import java.util.concurrent.Executors;/** * Created by teeyoung on 17/10/28. */public class DisruptorWizardMain2 {    private static final Translator TRANSLATOR = new Translator();    public static void main(String[] args) throws InterruptedException {        Executor executor = Executors.newCachedThreadPool();        int bufferSize = 1024;        EventHandler h1a = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("h1a : " + event.getValue());            }        };        EventHandler h1b = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("h1b : " + event.getValue() + " arrived. H1a should have completed. Completed.");            }        };        EventHandler h2a = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("h2a : " + event.getValue());            }        };        EventHandler h2b = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("h2b : " + event.getValue() + " arrived. H2a should have completed. Completed.");            }        };        EventHandler lastHandler = new EventHandler<LongEvent>() {            @Override            public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {                System.out.println("lastHandler : " + event.getValue() + " arrived. H1a, h1b, h2a and h2b should have completed. Completed.\n");            }        };        Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent::new, bufferSize, executor);        disruptor.handleEventsWith(h1a, h2a);        disruptor.after(h1a).then(h1b);        disruptor.after(h2a).then(h2b);        disruptor.after(h1b, h2b).then(lastHandler);        disruptor.start();        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();        ByteBuffer bb = ByteBuffer.allocate(8);        for (long l = 0; true; l++) {            bb.putLong(0, l);            ringBuffer.publishEvent(TRANSLATOR, bb);            Thread.sleep(1000);        }    }}

其中主要关注

disruptor.handleEventsWith(h1a, h2a);disruptor.after(h1a).then(h1b);disruptor.after(h2a).then(h2b);disruptor.after(h1b, h2b).then(lastHandler);

这就是领域特定语言(DSL),定义了消费顺序。
结果:

微信扫码关注订阅号,获取更多精彩内容

原创粉丝点击