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

  1. Run exactly one thread per processor instance: create a fresh MultiBufferBatchEventProcessor (or submit the single instance once) instead of resubmitting it.
  2. If restarting after halt(), first join/interrupt the old thread and confirm processor.isRunning() == false before calling run() again.
  3. 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.
  4. 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

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


AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14). Data as JSON: /api/errors/5e68b8944dd2c5fd. Report an issue: GitHub.