问题
Disruptor github address is: https://github.com/LMAX-Exchange/disruptor
I've a simple test for it as below:
public class DisruptorMain {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws Exception {
class Element {
private int value;
public int get() {
return value;
}
public void set(int value) {
this.value = value;
}
}
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "simpleThread");
}
};
EventFactory<Element> factory = new EventFactory<Element>() {
@Override
public Element newInstance() {
return new Element();
}
};
EventHandler<Element> handler = new EventHandler<Element>() {
@Override
public void onEvent(Element element, long sequence, boolean endOfBatch) {
try {
Thread.sleep(1000 * sequence);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Element: " + element.get());
}
};
BlockingWaitStrategy strategy = new BlockingWaitStrategy();
int bufferSize = 4;
Disruptor<Element> disruptor = new Disruptor(factory, bufferSize, threadFactory, ProducerType.SINGLE, strategy);
disruptor.handleEventsWith(handler);
disruptor.start();
RingBuffer<Element> ringBuffer = disruptor.getRingBuffer();
for (int l = 0; l < 8; l++) {
long sequence = ringBuffer.next();
System.out.println("sequence:" + sequence);
try {
Element event = ringBuffer.get(sequence);
event.set(l);
} finally {
ringBuffer.publish(sequence);
}
}
}
}
The result is: sequence:0 sequence:1 sequence:2 sequence:3 Element: 0 Element: 1 Element: 2 Element: 3 sequence:4 sequence:5 sequence:6 sequence:7 Element: 4 Element: 5 Element: 6 Element: 7
in my test, I've defined a ringbuffer size of 4, and I have a producer to create 8 tasks for it, my question is, when the producer have put 4 tasks in the ringbuffer, the consumer begins to take task from the ringbuffer to work, after task 1 finish, the ringbuffer should have an empty space for the task 5, but the result shows that, only if all of the tasks have been finished in the ringbuffer, the ringbuffer can accept the new task, why?
回答1:
This is because the Disruptor will batch in the event handler. If the event handler is slow or the ring buffer is small the batch size can often be the size of the ring buffer. The Disruptor will only update the processed sequence for that event handler until the batch is complete. This reduces the number of updates that it needs to make to the sequence variable used by the publisher to determine if space is available. If you need to make space available earlier than the default then you can do that using a SequenceReportingEventHandler.
public class MyEventHandler implements SequenceReportingEventHandler<Element> {
Sequence processedSequence;
public void setSequenceCallback(Sequence s) {
processedSequence = s;
}
public void onEvent(Element e, long sequence, boolean endOfBatch) {
// Do stuff
processedSequence.set(sequence);
}
}
来源:https://stackoverflow.com/questions/48352411/why-my-disruptor-program-dont-take-full-advantage-of-the-ringbuffer