原文链接: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),定义了消费顺序。
结果:
微信扫码关注订阅号,获取更多精彩内容