Unlock Ultra‑Low Latency Messaging with LMAX Disruptor: A Step‑by‑Step Java Guide

This article walks through the background, core concepts, and a complete hands‑on demo of LMAX Disruptor, showing how to configure Maven, implement ring buffers, event factories, handlers, producers, and a test suite to achieve high‑throughput, lock‑free messaging in Java.

Architect
Architect
Architect
Unlock Ultra‑Low Latency Messaging with LMAX Disruptor: A Step‑by‑Step Java Guide

Background

When a project required a fast in‑memory message queue, Disruptor was selected instead of traditional brokers such as Kafka or RabbitMQ because its primary advantage is raw speed and it is open‑source.

What is Disruptor?

Disruptor was created by the UK foreign‑exchange trading firm LMAX to eliminate the latency of memory queues that, in performance tests, approached the magnitude of I/O latency. A single‑threaded LMAX system can process six million orders per second. The framework gained industry attention after a 2010 QCon presentation. It is a Java library designed to maximize throughput (TPS) and minimize latency for the producer‑consumer problem.

GitHub repository: https://github.com/LMAX-Exchange/disruptor

Core Concepts

Ring Buffer – a circular buffer that stores events. Since version 3.0 its role is limited to storing and updating events; advanced use‑cases can replace it with a custom implementation.

Sequence – a monotonically increasing number that tracks the progress of a specific consumer (or RingBuffer) and prevents false sharing between CPUs.

Sequencer – the core lock‑free algorithm. Two implementations exist: SingleProducerSequencer and MultiProducerSequencer, defining how producers hand events to consumers.

Sequence Barrier – holds references to the main published sequence and dependent consumer sequences, deciding whether a consumer can advance.

Wait Strategy – determines how a consumer waits for the next event (e.g., blocking, yielding, sleeping). Different strategies give different latency‑throughput trade‑offs.

Event – the data object exchanged between producer and consumer; its type is defined by the user.

EventProcessor – owns a consumer’s sequence and runs the event‑loop that invokes the handler.

EventHandler – user‑implemented interface that processes each event; this is the actual consumer logic.

Producer – any code that publishes events to the Disruptor; no special interface is required.

Demo – Step‑by‑Step Implementation

The following eight‑step Maven‑based example builds a complete Disruptor pipeline.

Add Maven dependency

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.4</version>
</dependency>

Message model

/**
 * Message body
 */
@Data
public class MessageModel {
    private String message;
}

EventFactory

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

EventHandler (consumer)

@Slf4j
public class HelloEventHandler implements EventHandler<MessageModel> {
    @Override
    public void onEvent(MessageModel event, long sequence, boolean endOfBatch) {
        try {
            // Simulate asynchronous processing
            Thread.sleep(1000);
            log.info("Consumer start processing");
            if (event != null) {
                log.info("Consumed message: {}", event);
            }
        } catch (Exception e) {
            log.info("Consumer failed");
        }
        log.info("Consumer end processing");
    }
}

Bean manager for Spring context

@Component
public class BeanManager implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        this.applicationContext = ctx;
    }
    public static ApplicationContext getApplicationContext() { return applicationContext; }
    public static Object getBean(String name) { return applicationContext.getBean(name); }
    public static <T> T getBean(Class<T> clazz) { return applicationContext.getBean(clazz); }
}

MQManager – creates RingBuffer and Disruptor

@Configuration
public class MQManager {
    @Bean("messageModel")
    public RingBuffer<MessageModel> messageModelRingBuffer() {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        HelloEventFactory factory = new HelloEventFactory();
        int bufferSize = 1024 * 256; // must be power of two
        Disruptor<MessageModel> disruptor = new Disruptor<>(
                factory, bufferSize, executor,
                ProducerType.SINGLE,
                new BlockingWaitStrategy());
        disruptor.handleEventsWith(new HelloEventHandler());
        disruptor.start();
        return disruptor.getRingBuffer();
    }
}

Service interface and implementation (producer)

public interface DisruptorMqService {
    /** Send a message */
    void sayHelloMq(String message);
}

@Slf4j
@Component
@Service
public class DisruptorMqServiceImpl implements DisruptorMqService {
    @Autowired
    private RingBuffer<MessageModel> messageModelRingBuffer;
    @Override
    public void sayHelloMq(String message) {
        log.info("record the message: {}", message);
        long sequence = messageModelRingBuffer.next();
        try {
            MessageModel event = messageModelRingBuffer.get(sequence);
            event.setMessage(message);
            log.info("Add message to queue: {}", event);
        } catch (Exception e) {
            log.error("failed to add event", e);
        } finally {
            // publish must be in finally to avoid blocking later producers
            messageModelRingBuffer.publish(sequence);
        }
    }
}

Test class

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class DemoApplicationTests {
    @Autowired
    private DisruptorMqService disruptorMqService;
    @Test
    public void sayHelloMqTest() throws Exception {
        disruptorMqService.sayHelloMq("Message arrived, Hello world!");
        log.info("Message queue sent");
        // Verify asynchronous processing
        Thread.sleep(2000);
    }
}

Test Run Output

2020-04-05 14:31:18.543  INFO 7274 --- [main] c.e.u.d.d.s.Impl.DisruptorMqServiceImpl : record the message: Message arrived, Hello world!
2020-04-05 14:31:18.545  INFO 7274 --- [main] c.e.u.d.d.s.Impl.DisruptorMqServiceImpl : Add message to queue: MessageModel(message=Message arrived, Hello world!)
2020-04-05 14:31:18.545  INFO 7274 --- [main] c.e.utils.demo.DemoApplicationTests : Message queue sent
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler : Consumer start processing
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler : Consumed message: MessageModel(message=Message arrived, Hello world!)
2020-04-05 14:31:19.547  INFO 7274 --- [pool-1-thread-1] c.e.u.d.disrupMq.mq.HelloEventHandler : Consumer end processing

Conclusion

The producer‑consumer pattern is ubiquitous, but Disruptor achieves higher performance because it operates entirely in memory with a lock‑free algorithm, eliminating the overhead of broker‑based queues. Its design—ring buffer, sequence barrier, and configurable wait strategies—allows a single thread to sustain millions of events per second, as demonstrated by the LMAX benchmark of six million orders per second.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyMessage QueueDisruptorhigh performance
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.