Introduction to Disruptor: A High‑Performance Java Message Queue with Full Example
This article introduces the open‑source Disruptor library, explains its core concepts such as Ring Buffer, Sequence, Sequencer and Wait Strategy, and provides a step‑by‑step Java demo—including Maven dependency, event model, handlers, configuration, producer, and test code—to show how to build a fast in‑memory message queue.
Disruptor Overview
Disruptor is an open‑source Java framework originally developed by LMAX Exchange to achieve ultra‑low latency and high throughput in producer‑consumer scenarios. It replaces traditional blocking queues with a lock‑free ring buffer, enabling millions of operations per second.
Core Concepts
1. Ring Buffer
A circular buffer that stores events; since version 3.0 it only handles storage and update of data.
2. Sequence
Monotonically increasing numbers that identify each event and track consumer progress, avoiding false sharing.
3. Sequencer
The central component with implementations for single‑producer and multi‑producer modes, providing the concurrency algorithm.
4. Sequence Barrier
Ensures consumers see only published events and coordinates dependencies between consumers.
5. Wait Strategy
Defines how a consumer waits for the next event; multiple strategies exist for different performance trade‑offs.
6. Event
The data object exchanged between producer and consumer; 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 each event.
9. Producer
Any code that publishes events to the Disruptor; no specific interface is required.
Demo Example (8 Steps)
1. Add Maven dependency:
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>2. Define the message model:
@Data
public class MessageModel {
private String message;
}3. Implement EventFactory :
public class HelloEventFactory implements EventFactory
{
@Override
public MessageModel newInstance() {
return new MessageModel();
}
}4. Create an EventHandler (consumer):
@Slf4j
public class HelloEventHandler implements EventHandler
{
@Override
public void onEvent(MessageModel event, long sequence, boolean endOfBatch) {
try {
Thread.sleep(1000); // simulate async processing
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");
}
}5. Provide a bean manager to obtain Spring beans:
@Component
public class BeanManager implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
public static ApplicationContext getApplicationContext() { return applicationContext; }
public static Object getBean(String name) { return applicationContext.getBean(name); }
public static
T getBean(Class
clazz) { return applicationContext.getBean(clazz); }
}6. Configure the Disruptor and expose a RingBuffer bean:
@Configuration
public class MQManager {
@Bean("messageModel")
public RingBuffer
messageModelRingBuffer() {
ExecutorService executor = Executors.newFixedThreadPool(2);
HelloEventFactory factory = new HelloEventFactory();
int bufferSize = 1024 * 256; // must be power of two
Disruptor
disruptor = new Disruptor<>(factory, bufferSize, executor,
ProducerType.SINGLE, new BlockingWaitStrategy());
disruptor.handleEventsWith(new HelloEventHandler());
disruptor.start();
return disruptor.getRingBuffer();
}
}7. Define the producer service interface and implementation:
public interface DisruptorMqService {
void sayHelloMq(String message);
}
@Slf4j
@Component
@Service
public class DisruptorMqServiceImpl implements DisruptorMqService {
@Autowired
private RingBuffer
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. Write a SpringBoot test to publish a message and observe the consumer logs:
@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); // wait for async consumer
}
}Test Output
The logs show the producer recording the message, the event being added to the ring buffer, and the consumer processing it asynchronously with start and end markers.
Conclusion
The producer‑consumer pattern is common, but Disruptor implements it entirely in memory without locks, which explains its exceptional performance for high‑throughput scenarios.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.