How Disruptor Achieves Lock-Free Speed: Single-Threaded Writes, Memory Barriers, and False Sharing

This article explains how the Disruptor library attains true lock‑free performance through single‑threaded writes, the use of memory barriers (volatile and happens‑before semantics), cache‑line alignment to eliminate false sharing, and a sequence‑barrier algorithm, providing code examples and practical optimization tips.

JavaEdge
JavaEdge
JavaEdge
How Disruptor Achieves Lock-Free Speed: Single-Threaded Writes, Memory Barriers, and False Sharing

1. Single‑Threaded Write

Disruptor’s RingBuffer achieves a completely lock‑free design by enforcing a strict single‑threaded writer. This premise is essential; without it no lock‑free guarantee can be made. High‑performance frameworks such as Redis and Netty adopt the same principle.

2. Memory‑Barrier Optimization

Lock‑free correctness also requires memory barriers. In Java this is expressed with volatile fields and the happens‑before guarantee.

Linux kernel example uses smp_wmb() / smp_rmb() for write/read barriers (e.g., kfifo implementation). URL: https://github.com/opennetworklinux/linux-3.8.13/blob/master/kernel/kfifo.c

3. Cache‑Line Optimization – Eliminating False Sharing

Modern CPUs store data in cache lines (typically 64 bytes). When independent variables share a cache line, false sharing degrades performance.

Core concept: Sequence

The Sequence object behaves like an AtomicLong that marks progress and is padded so that its value occupies a full cache line (8 longs = 64 bytes), preventing false sharing.

4. Algorithmic Optimization – Sequence Barrier Mechanism

When a producer publishes an event it obtains a slot with: long sequence = ringBuffer.next(); In Disruptor 3.0 the SequenceBarrier works with Sequence to coordinate producer and consumer progress without locks or CAS.

Consumer sequence must be less than the producer sequence.

Consumer sequence must be less than any upstream consumer’s sequence.

Producer sequence cannot advance beyond the smallest consumer sequence.

This prevents overwriting events that have not yet been consumed.

SingleProducerSequencerPad#next Implementation (Java)

/** @see Sequencer#next(int) */
@Override
public long next(int n) {
    if (n < 1) {
        throw new IllegalArgumentException("n must be > 0");
    }
    // nextValue is a field of SingleProducerSequencer
    long nextValue = this.nextValue;
    long nextSequence = nextValue + n;
    long wrapPoint = nextSequence - bufferSize; // check wrap‑around
    long cachedGatingSequence = this.cachedValue;
    if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue) {
        long minSequence;
        while (wrapPoint > (minSequence = Util.getMinimumSequence(gatingSequences, nextValue))) {
            LockSupport.parkNanos(1L); // optional spin‑wait strategy
        }
        this.cachedValue = minSequence;
    }
    this.nextValue = nextSequence;
    return nextSequence;
}

Further discussion can be found at: https://zhuanlan.zhihu.com/p/21355046

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.

Disruptorfalse sharinglock‑freeJava concurrencymemory barriers
JavaEdge
Written by

JavaEdge

First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.

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.