Disruptor的具体原理 http://ifeve.com/disruptor/
通过cache line对齐来解决 false sharing的问题,而且是无锁的,应该比java自带的blocking queue速度要快。
这个Disruptor库用来解决生产者和消费者问题,它可以实现生产者和消费者 N:M的关系。
可实现的模式有 菱形(disruptor.handleEventsWith(c0,c1).then(c2) )
*
* +----+
* +----->| C0 |-----+
* | +----+ |
* | v
* +----+ +----+
* | P0 | | C2 |
* +----+ +----+
* | ^
* | +----+ |
* +----->| C1 |-----+
* +----+
*
管道(isruptor.handleEventsWith(c0).then(c1).then(c2))
* +----+ +----+ +----+ +----+
* | P0 |--->| C0 |--->| C1 |--->| C2 |
* +----+ +----+ +----+ +----+
后面的消费者要等到前面的消费者处理完后,才会处理该消息。菱形状态下,C0和C1并发运行,但处理的消息都是一样的。也就是说,一个生产者产生的同一个数据都会被
C0和C1处理,而不会只有C0或者C1处理。并行的意思是C0,C1,C2在不同的线程中。disruptor会为每个消费者分配一个线程。
要注意ringbuffer的分配的大小,ringbuffer不应该太大。如果你需要一个很大的ringbuffer,说明消费者线程这边处理能力不够,需要提高消费者处理线程能力。
当然也有可能是生产者这边burst的比较厉害。消费者消费完数据后,ringbuffer仍旧引用你的数据,导致Jvm无法回收这些内存。如果确实为应对生产者的burst,而
申请一个大的ringbuffer,注意在Evnet中清理数据。这个可以通过加一个消费者,最后一个消费者处理event中引用的数据即可。
MainDisruptor.java
package example1;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
public class MainDisruptor {
public static void main(String[] args) {
// TODO Auto-generated method stub
//ExecutorService executor = Executors.newFixedThreadPool(1);
Disruptor<LogEvent> disruptor = new Disruptor<LogEvent>(new MyFactory(), 4, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
System.out.println("create new thread " + t.getId());
return t;
}
},
ProducerType.SINGLE,
new BlockingWaitStrategy());
new MyEventHandler(0);
//产生三个消费者线程
disruptor.handleEventsWith( new MyEventHandler(0), new MyEventHandler(1) ).then( new MyEventHandler(3));
disruptor.start();
for(int i=0; i<10; i++) {
MyData data = new MyData();
data.orderID = i;
data.price = Math.random();
disruptor.publishEvent( new MyEventTranslatorOneArg(), data);
}
disruptor.shutdown();
}
}
LogEvent.java
public class LogEvent {
private MyData data;
public void setValue(MyData data) {
this.data = data;
}
public MyData getData() {
return this.data;
}
public String toString() {
return "LogEvent";
}
}
MyData.java
public class MyData {
public int orderID;
public double price;
public String toString() {
return String.format("orderID %d, price %f", orderID, price);
}
}
MyEventHandler.java
import com.lmax.disruptor.EventHandler;
public class MyEventHandler implements EventHandler<LogEvent> {
private int tag;
public MyEventHandler(int tag) {
this.tag = tag;
}
@Override
public void onEvent(LogEvent event, long sequence, boolean endofBatch) throws Exception {
// TODO Auto-generated method stub
System.out.println("onEvent " + sequence + " tag " + this.tag + " threadID " + Thread.currentThread().getId() + " " + endofBatch);
}
}
MyEventTranslatorOneArg.java
import com.lmax.disruptor.EventTranslatorOneArg;
public class MyEventTranslatorOneArg implements EventTranslatorOneArg<LogEvent, MyData> {
@Override
public void translateTo(LogEvent event, long sequence, MyData data) {
System.out.println(" assit publish event sequence " + sequence + " threadID " + Thread.currentThread().getId());
event.setValue(data);
}
}
MyFactory.java
import com.lmax.disruptor.EventFactory;
public class MyFactory implements EventFactory<LogEvent> {
@Override
public LogEvent newInstance() {
// TODO Auto-generated method stub
return new LogEvent();
}
}