LMAX-Exchange/disruptor · error · RuntimeException
Already running
Error message
Already running
What it means
RuntimeException thrown by MultiBufferBatchEventProcessor.run (src/perftest/java/com/lmax/disruptor/support/MultiBufferBatchEventProcessor.java:49) when run() is entered while the processor is already running. The processor guards its single-consumer loop with an AtomicBoolean compareAndSet(false, true); a second concurrent invocation cannot acquire it. Note this class is a perftest support utility, not the production DSL path.
Source
Thrown at src/perftest/java/com/lmax/disruptor/support/MultiBufferBatchEventProcessor.java:49
}
this.providers = providers;
this.barriers = barriers;
this.handler = handler;
this.sequences = new Sequence[providers.length];
for (int i = 0; i < sequences.length; i++)
{
sequences[i] = new Sequence(-1);
}
}
@Override
public void run()
{
if (!isRunning.compareAndSet(false, true))
{
throw new RuntimeException("Already running");
}
for (SequenceBarrier barrier : barriers)
{
barrier.clearAlert();
}
final int barrierLength = barriers.length;
while (true)
{
try
{
for (int i = 0; i < barrierLength; i++)
{
long available = barriers[i].waitFor(-1);
Sequence sequence = sequences[i];
View on GitHub (pinned to c871ca4982)
Solutions
- Run exactly one thread per processor instance: create a fresh MultiBufferBatchEventProcessor (or submit the single instance once) instead of resubmitting it.
- If restarting after halt(), first join/interrupt the old thread and confirm processor.isRunning() == false before calling run() again.
- If the executor may re-run tasks, wrap the processor in a dedicated Thread created per lifecycle rather than passing the processor itself as a repeating Runnable.
- For production use, prefer the supported DSL (Disruptor / BatchEventProcessor / WorkerPool) instead of this perftest support class, since it lacks the lifecycle management of the main library.
Example fix
// before: same instance submitted twice -> second run() throws "Already running"
executor.submit(processor);
executor.submit(processor); // RuntimeException
// after: one instance per run, wait for shutdown before restarting
executor.submit(processor);
// ... to restart later:
processor.halt();
while (processor.isRunning()) { Thread.onSpinWait(); }
executor.submit(new MultiBufferBatchEventProcessor<>(providers, barriers, handler)); Defensive patterns
Strategy: validation
Validate before calling
// Before (re)submitting the processor, check its lifecycle state
if (processor.isRunning()) {
throw new IllegalStateException("MultiBufferBatchEventProcessor is already running; halt it and wait for exit before restarting");
}
executor.submit(processor); Try / catch
try {
executor.submit(processor);
} catch (RuntimeException e) {
if ("Already running".equals(e.getMessage())) {
log.warn("Processor already running; skipping duplicate start");
} else {
throw e;
}
} Prevention
- Own the lifecycle: submit each EventProcessor instance to exactly one thread and never reuse the instance as a repeating task.
- On restart, call halt() and wait until isRunning() returns false (join the old thread) before invoking run() again.
- Keep application logic on the production DSL (Disruptor/BatchEventProcessor/WorkerPool) rather than perftest support classes with hand-rolled lifecycle guards.
When it happens
Trigger: Submitting the same MultiBufferBatchEventProcessor instance to an executor twice (e.g. two executor.submit(processor) calls), or calling run() directly on a thread while it is already executing. Also restarting the processor by calling run() again without the previous loop having exited after halt() (halt() sets isRunning false, so a genuine restart works only after the old loop has observed the alert and returned).
Common situations: Porting the multi-buffer perftest pattern into application code and wiring the processor into a ScheduledExecutorService that re-runs tasks, causing overlapping executions; a supervisor/health-check loop that 'restarts' consumers by calling run() while the old thread is still inside the while(true) loop; copy-pasting benchmark scaffolding where the processor instance is a shared field.
Related errors
- Thread is already running
- setDefaultExceptionHandler can not be used after handleExcep
- All event handlers must be added before calling starts.
- Disruptor.start() must only be called once.
- Failed to create thread to run: {}
AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14).
Data as JSON: /api/errors/5e68b8944dd2c5fd.
Report an issue: GitHub.