Mastering Disruptor: High‑Performance Java Queue for Producer‑Consumer Systems

This article introduces the open‑source Disruptor framework, explains its core concepts such as Ring Buffer, Sequencer, and Wait Strategies, and provides a step‑by‑step Java demo—including Maven setup, event factory, handlers, and a test case—to illustrate building a high‑throughput, low‑latency in‑memory message queue.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Mastering Disruptor: High‑Performance Java Queue for Producer‑Consumer Systems

1 Background

In a project we needed a fast in‑memory message queue and chose Disruptor, an open‑source library known for its speed.

2 Disruptor Overview

Disruptor was developed by LMAX, a UK foreign‑exchange trading company, to solve latency problems of traditional memory queues, achieving performance comparable to I/O operations.

Systems built on Disruptor can process six million orders per second on a single thread.

It is a Java framework designed to maximize throughput (TPS) and minimize latency for the producer‑consumer problem.

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

Beyond finance, Disruptor can significantly improve performance in general applications.

It is more a design pattern than a conventional framework, offering a high‑performance solution for concurrent, buffered, producer‑consumer, or transactional programs.

3 Core Concepts of Disruptor

1. Ring Buffer

The circular buffer that stores events. Since version 3.0 its responsibility is limited to storing and updating data; users can replace it with custom implementations.

2. Sequence

Sequences assign incremental numbers to events, ensuring they are processed in order. A Sequence tracks the progress of a specific consumer.

Preventing false sharing between sequences is a key performance factor.

3. Sequencer

The heart of Disruptor. Implementations such as SingleProducerSequencer and MultiProducerSequencer define the concurrent algorithm that passes data between producers and consumers.

4. Sequence Barrier

Maintains references to the main published sequence of the RingBuffer and the sequences of dependent consumers, determining whether a consumer has events to process.

5. Wait Strategy

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

6. Event

In Disruptor terminology, the data exchanged between producer and consumer is called an Event. Its type is defined by the user.

7. EventProcessor

Holds a consumer’s Sequence and runs the event‑handling loop.

8. EventHandler

User‑implemented interface that processes events; it is the actual consumer implementation.

9. Producer

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

4 Demo – Step‑by‑Step Implementation

Follow these eight steps to set up Disruptor in a Spring Boot project.

1. Add Maven Dependency

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

2. Define Message Model

@Data
public class MessageModel {
    private String message;
}

3. Create EventFactory

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

4. Implement EventHandler (Consumer)

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

5. BeanManager for ApplicationContext

@Component
public class BeanManager implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        BeanManager.applicationContext = applicationContext;
    }
    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);
    }
}

6. Configure RingBuffer (MQManager)

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

7. Service Interface and Implementation (Producer)

public interface DisruptorMqService {
    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);
        }
    }
}

8. 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");
        Thread.sleep(2000);
    }
}

Running the test produces logs that show the producer recording the message, the consumer processing it asynchronously, and the overall flow completing successfully.

5 Summary

The producer‑consumer pattern is common, and many message‑queue solutions can achieve it, but Disruptor implements the queue entirely in memory without locks, which explains its exceptional performance.

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.

JavaMessage QueueDisruptorhigh performanceProducer ConsumerRing Buffer
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.