本篇为disruptor的一个demo,帮助大家快速入门使用起来,下面的代码是一个简单的实现,可以跟着本地debug进行源码查看一下具体的事件处理过程
先了解一下步骤:
- 建立一个Event类
- 建立一个工厂Event类,用于创建Event类实例对象
- 需要有一个监听事件类,用于处理数据(Event类)
- 我们需要进行测试代码编写。实例化Disruptor实例,配置参数。然后我们对Disruptor实例绑定监听事件类,接受并处理数据。
- 在Disruptor中,真正存储数据的核心叫做RingBuffer,我们通过Disruptor实例拿到它,然后把数据生产出来,把数据加入到RingBuffer的实例对象中即可
package com.lxj.disruptor;
/*
* 用于传递数据的对象
*/
public class StringEvent {
private Integer id;
private String value;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "StringEvent [id=" + id + ", value=" + value + "]";
}
}
package com.lxj.disruptor;
import com.lmax.disruptor.EventFactory;
/*
* 实现Disruptor提供的工厂接口,工厂方法模式
*/
public class StringEventFactory implements EventFactory<StringEvent> {
@Override
public StringEvent newInstance() {
//我们自定义的对象
return new StringEvent();
}
}
package com.lxj.disruptor;
import com.lmax.disruptor.EventHandler;
/*
* 事件的处理器,也就是消费者,这里模拟的是将数据打印处理
*/
public class StringEventHandler implements EventHandler<StringEvent> {
@Override
public void onEvent(StringEvent stringEvent, long sequence, boolean bool) throws Exception {
System.out.println("StringEventHandler(消费者): " + stringEvent +", sequence= "+sequence+",bool="+bool);
}
}
package com.lxj.disruptor;
import java.nio.ByteBuffer;
import com.lmax.disruptor.RingBuffer;
/*
* 这是一个事件源,模拟的就是网络或者磁盘IO发送数据过来,触发事件
* ByteBuffer中携带着数据
*/
public class StringEventProducer {
private final RingBuffer<StringEvent> ringBuffer;
public StringEventProducer(RingBuffer<StringEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
}
public void sendData(ByteBuffer byteBuffer) {
//ringBuffer就是用来存储数据的,具体可以看disruptor源码的数据结构,next就是获取下一个空事件索引
long sequence = ringBuffer.next();
try {
//通过索引获取空事件
StringEvent stringEvent = ringBuffer.get(sequence);
//切换成读模式
byteBuffer.flip();
//从byteBuffer中读取传过来的值
byte[] dst = new byte[byteBuffer.limit()];
byteBuffer.get(dst, 0, dst.length);
//为stringEvent赋值,填充数据
stringEvent.setValue(new String(dst));
stringEvent.setId((int) sequence);
//clear一下缓冲区
byteBuffer.clear();
} finally {
//发布事件,为确保安全,放入finally中,不会造成disruptor的混乱
ringBuffer.publish(sequence);
}
}
}
package com.lxj.disruptor;
import java.nio.ByteBuffer;
import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer;
/*
* 一个Translator可以看做一个事件初始化器
*/
public class StringEventProducerWithTranslator {
private final RingBuffer<StringEvent> ringBuffer;
//填充数据
public static final EventTranslatorOneArg<StringEvent, ByteBuffer> TRANSLATOR = new EventTranslatorOneArg<StringEvent, ByteBuffer>() {
@Override
public void translateTo(StringEvent stringEvent, long sequence, ByteBuffer byteBuffer) {
// 从byteBuffer中读取传过来的值
byteBuffer.flip();
byte[] dst = new byte[byteBuffer.limit()];
byteBuffer.get(dst, 0, dst.length);
byteBuffer.clear();
// 为stringEvent赋值,填充数据
stringEvent.setValue(new String(dst));
stringEvent.setId((int) sequence);
}
};
public StringEventProducerWithTranslator( RingBuffer<StringEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
}
//发布事件
public void sendData(ByteBuffer byteBuffer) {
ringBuffer.publishEvent(TRANSLATOR, byteBuffer);
}
}
package com.lxj.disruptor;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
/*
* 测试主函数
*/
public class StringEventMain {
public static void main(String[] args) throws Exception {
//创建一个线程池
ExecutorService executorPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
//创建Event工厂
StringEventFactory factory = new StringEventFactory();
/*
* 创建Disruptor对象
* eventFactory, 传入实现了EventFactory借口的工厂类
* ringBufferSize, 用来存储数据的, 值为 2^n
* executor, 线程池
* producerType, 类型,可以是多个生产者,也可以是单个生产者
* waitStrategy, 使用什么策略,消费者如何等待生产者放入disruptor中 :
BlockingWaitStrategy 是最低效的策略,但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现
SleepingWaitStrategy 的性能表现跟BlockingWaitStrategy差不多,对CPU的消耗也类似,但其对生产者线程的影响最小,适合用于异步日志类似的场景
YieldingWaitStrategy 的性能是最好的,适合用于低延迟的系统。在要求极高性能且事件处理线数小于CPU逻辑核心数的场景中,推荐使用此策略;例如,CPU开启超线程的特性
*/
Disruptor<StringEvent> disruptor = new Disruptor<>(factory, (int)Math.pow(2, 20), executorPool, ProducerType.SINGLE, new YieldingWaitStrategy());
//关联处理器,也就是消费者,连接消费事件方法
disruptor.handleEventsWith(new StringEventHandler());
//启动
disruptor.start();
//获取RingBuffer,模拟生产者发布消息
RingBuffer<StringEvent> ringBuffer = disruptor.getRingBuffer();
StringEventProducerWithTranslator producer = new StringEventProducerWithTranslator(ringBuffer);
//StringEventProducer producer = new StringEventProducer(ringBuffer);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//闭锁控制线程同步
CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0 ; i < 10 ; i ++) {
//下面是进行触发事件并且发布
byteBuffer.put(new String("生产者"+ i +"发布消息").getBytes());
producer.sendData(byteBuffer);
//模拟进行其他操作的耗时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
countDownLatch.countDown();
}
},"Thread2").start();;
//等待
countDownLatch.await();
disruptor.shutdown(); //关闭 disruptor
executorPool.shutdown(); //关闭线程池
}
}