Disruptor learning - easy to use

Keywords: Java github Programming Lambda

Destructor GitHub address

Introduction: disruptor is an open source and efficient concurrent framework

event: event
Event factory: eventFactory
The concrete implementation of event handling: eventHandler
Producer

In order to use disruptor, let's consider a simple example, which is to say = pass a long type number to the consumer through the producer, and the consumer will simply print out the value

jar package: the latest version is 3.4.2. Here we use 3.4.1, because 3.4.2 is developed based on Java11, I use Java8, and errors will be reported when compiling (the version number 55.0 with errors in class files should be 52.0)

  <!--disruptor Concurrent programming framework -->
        <dependency>
            <groupId>com.weicoder</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.1</version>
        </dependency>

Step 1: define events

public class LongEvent {
    private long value;

    public void set(long value) {
        this.value = value;
    }
}

Step 2: define the event factory

import com.lmax.disruptor.EventFactory;

public class LongEventFactory implements EventFactory<LongEvent> {
    @Override
    public LongEvent newInstance() {
        return new LongEvent();
    }
}

Step 3: define event handler (once we define an event, we need to create a consumer to handle these events. In our case, we just want to print the value on the console)

import com.lmax.disruptor.EventHandler;

public class LongEventHandler implements EventHandler<LongEvent> {

    @Override
    public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception {
        System.out.println("Event" + event);
    }
}

Step 4: define the producer (in the 3.0 version of Disruptor, a richer lambda style API has been added to help developers encapsulate complex ring buffers, so the preferred way to publish messages after 3.0 is through the Event Publisher/Event Translator part of the API. Another point of this method is that the translator code can be placed in a separate class It can easily complete independent unit tests. The Disruptor provides many different interfaces (eventtranslator, eventtranslator one Arg, eventtranslator two Arg, etc.) which can be implemented)

import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer;

import java.nio.ByteBuffer;

public class LongEventProducerWithTranslator {

    private final RingBuffer<LongEvent> ringBuffer;

    public LongEventProducerWithTranslator(RingBuffer<LongEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR =
            (event, sequence, bb) -> event.set(bb.getLong(0));

    public void oneData(ByteBuffer bb){
        ringBuffer.publishEvent(TRANSLATOR,bb);
    }

}

The producer also has an older, more primitive method, which is more complex than using simple queues. This is because events need to be preallocated. It requires (at the lowest level) a two-stage method of message publishing, that is, declaring the timeslot in the ring buffer, and then publishing the available data. This requires wrapping the publishing in the try/finally block. If I If you declare a slot (RingBuffer.next()) in this ring buffer, you must publish this sequence. If you do not, in the case of multi producers, this will cause consumer stagnation and cannot be restarted and cannot be recovered. Therefore, it is recommended to use the EventTranslator API, which is the above method

import com.lmax.disruptor.RingBuffer;
import java.nio.ByteBuffer;

public class LongEventProducer {

    private  final RingBuffer<LongEvent> ringBuffer;

    public LongEventProducer(RingBuffer<LongEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    public void oneData(ByteBuffer bb){
        long sequence = ringBuffer.next();
        try{
            LongEvent event = ringBuffer.get(sequence);
            event.set(bb.getLong(0));
        }finally {
            ringBuffer.publish(sequence);
        }
    }
}

Step 5: connect the whole process. All components can be connected manually

import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.util.DaemonThreadFactory;

import java.nio.ByteBuffer;
public class LongEventMain {
    public static void main(String[] args) throws InterruptedException {

        //Event factory
        LongEventFactory factory = new LongEventFactory();

        //Specifies the ring buffer size, which must be a power of 2
        int bufferSize = 1024;

        //Constructor for Disruptor
        Disruptor<LongEvent> disruptor = new Disruptor<>(factory, bufferSize, DaemonThreadFactory.INSTANCE);

        //Connecting the processor
        disruptor.handleEventsWith(new LongEventHandler());

        //Start Disruptor, all threads start
        disruptor.start();

        //Get ring buffer from Disruptor for publishing
        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();

        LongEventProducerWithTranslator producer = new LongEventProducerWithTranslator(ringBuffer);
        ByteBuffer bb =  ByteBuffer.allocate(8);
        for (long l = 0; true; l++) {
            bb.put(0, (byte) l);
            producer.oneData(bb);
            Thread.sleep(1000);
        }
    }
}

Output result

Eventcom.chunqiu.elasticsearchlearn.disruptor.LongEvent@193c30a5
Eventcom.chunqiu.elasticsearchlearn.disruptor.LongEvent@79eb6ada
Eventcom.chunqiu.elasticsearchlearn.disruptor.LongEvent@286f6ab3
Eventcom.chunqiu.elasticsearchlearn.disruptor.LongEvent@1526e7d
Eventcom.chunqiu.elasticsearchlearn.disruptor.LongEvent@7913cfea
......
Published 18 original articles, won praise 6, visited 70000+
Private letter follow

Posted by Sanoz0r on Thu, 16 Jan 2020 00:39:44 -0800