Backend Development 12 min read

Mastering Disruptor: Build a High‑Performance Java Message Queue in 8 Steps

This article introduces the Disruptor library, explains its core concepts such as Ring Buffer, Sequencer, and Wait Strategy, and provides a complete eight‑step Spring Boot example with code to create, publish, and consume high‑throughput messages in Java.

macrozheng
macrozheng
macrozheng
Mastering Disruptor: Build a High‑Performance Java Message Queue in 8 Steps

Background

In a project we needed a fast message queue and chose Disruptor, an open‑source Java framework known for its extreme speed.

Disruptor Overview

Disruptor was developed by LMAX, a UK foreign‑exchange trading firm, to solve memory‑queue latency and can handle millions of orders per second.

It is a Java framework designed to achieve maximum throughput and minimal latency for the producer‑consumer problem.

Functionally it implements a bounded queue, making it suitable for any producer‑consumer scenario.

LMAX uses it to process 6 million TPS; it can improve performance in many other domains.

Disruptor is more a design pattern than a traditional framework, offering a high‑performance solution for concurrent, buffered, transactional workloads.

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

Core Concepts of Disruptor

The following domain objects map directly to the code implementation.

Ring Buffer

The circular buffer that stores events; since version 3.0 its responsibility is limited to storing and updating data.

Sequence

Sequences are monotonically increasing numbers that identify each event and track consumer progress, avoiding false sharing.

Sequencer

The heart of Disruptor, with implementations

SingleProducerSequencer

and

MultiProducerSequencer

, defines the fast, correct concurrency algorithm.

Sequence Barrier

Maintains references to the main published sequence and dependent consumer sequences, determining if a consumer can process more events.

Wait Strategy

Specifies how a consumer waits for the next event; Disruptor provides several strategies with different performance characteristics.

Event

Data exchanged between producer and consumer; the type is defined by the user.

EventProcessor

Holds a consumer’s sequence and runs the event loop that invokes the user‑provided handler.

EventHandler

User‑implemented interface that processes each event.

Producer

Any code that publishes events to Disruptor; no specific interface is required.

Example Implementation (8 Steps)

Follow these steps to integrate Disruptor into a Spring Boot project.

Add the Maven dependency:

<code>&lt;dependency&gt;
    &lt;groupId&gt;com.lmax&lt;/groupId&gt;
    &lt;artifactId&gt;disruptor&lt;/artifactId&gt;
    &lt;version&gt;3.3.4&lt;/version&gt;
&lt;/dependency&gt;</code>

Create the message model:

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

Implement the

EventFactory

:

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

Implement the consumer (

EventHandler

):

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

Create a bean manager to obtain Spring beans:

<code>/** Get Spring beans */
@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); }
}</code>

Configure the Disruptor bean:

<code>@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();
    }
}
</code>

Define the service interface and implementation (producer):

<code>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 {
            messageModelRingBuffer.publish(sequence);
        }
    }
}
</code>

Write a Spring Boot test to publish a message:

<code>@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");
        Thread.sleep(2000); // ensure async processing
    }
}
</code>

Test output demonstrates the producer logging the message, the consumer processing it asynchronously, and the overall flow completing without blocking.

Conclusion

The producer‑consumer pattern is common, and many message‑queue solutions can achieve similar results, but Disruptor implements it entirely in memory with a lock‑free design, which is why it delivers such high efficiency.

JavaconcurrencySpring BootMessage QueueDisruptorhigh performance
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login 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.