Disruptor 源码解析

本文的一些理解基于http://ifeve.com/?x=29&y=10&s=disruptor 一系列文章

disruptor 版本 3.4.2

RingBuffer  维护并发数据的缓冲数组

 

RingBuffer

因为一些相关参数都用到了,把这几个步骤一起说明,利于理解

静态模块初始化 + RingBufferFields构造函数

    private static final int BUFFER_PAD;//缓冲器填充padding
    private static final long REF_ARRAY_BASE;//数组对象头信息 + BUFFER_PAD * 引用指针大小  字节
    private static final int REF_ELEMENT_SHIFT;//引用指定大小  字节
    private static final Unsafe UNSAFE = Util.getUnsafe();

    static
    {
        final int scale = UNSAFE.arrayIndexScale(Object[].class);
        if (4 == scale)//开启指针压缩,引用大小为4字节
        {
            REF_ELEMENT_SHIFT = 2;
        }
        else if (8 == scale)//64位 未开启指针压缩,引用大小为8字节
        {
            REF_ELEMENT_SHIFT = 3;
        }
        else
        {
            throw new IllegalStateException("Unknown pointer size");
        }
        BUFFER_PAD = 128 / scale;//默认除了数组头信息外 再填充128个字节
        // Including the buffer pad in the array base offset
        REF_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class) + (BUFFER_PAD << REF_ELEMENT_SHIFT);
    }

    private final long indexMask;//bufferSize-1  非数组length - 1!!!
    private final Object[] entries;
    protected final int bufferSize;
    protected final Sequencer sequencer;

    RingBufferFields(
        EventFactory eventFactory,
        Sequencer sequencer)
    {
        this.sequencer = sequencer;
        this.bufferSize = sequencer.getBufferSize();

        if (bufferSize < 1)
        {
            throw new IllegalArgumentException("bufferSize must not be less than 1");
        }
        if (Integer.bitCount(bufferSize) != 1)//ringbuffer的大小为2的幂次方
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        this.indexMask = bufferSize - 1;
        this.entries = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];//数组实际元素个数所占字节 + 128 * 2 字节  即开启指针压缩情况下,多64个元素,未开启指针压缩情况下,多32个元素
        fill(eventFactory);
    }

    private void fill(EventFactory eventFactory)
    {
        for (int i = 0; i < bufferSize; i++)
        {
            entries[BUFFER_PAD + i] = eventFactory.newInstance();//数组从第33个元素或者第17个元素开始填充
        }
    }

看到fille函数的初始化就应该会发现 获取元素的方式肯定也有一些文章

    protected final E elementAt(long sequence)
    {//REF_ARRAY_BASE 数组初始化多填充了2 * BUFFER_PAD,前一个BUFFER_PAD所占字节就是在REF_ARRAY_BASE里
        return (E) UNSAFE.getObject(entries, REF_ARRAY_BASE + ((sequence & indexMask) << REF_ELEMENT_SHIFT));
    }//这样的设计应该就是解决伪共享,预读数组,求余操作优化

ConsumerInfo

消费者信息  包含:消费者执行器、Handler以及前置SequenceBarrier

具体实现类

EventProcessInfo

class EventProcessorInfo implements ConsumerInfo
{
    private final EventProcessor eventprocessor;
    private final EventHandler handler;
    private final SequenceBarrier barrier;
    private boolean endOfChain = true;

    EventProcessorInfo(
        final EventProcessor eventprocessor, final EventHandler handler, final SequenceBarrier barrier)
    {
        this.eventprocessor = eventprocessor;
        this.handler = handler;
        this.barrier = barrier;
    }
}

 

ConsumerRepository

RingBuffer中维护Handler(即消费者)的数据结构

内部有两个IdentityHashMap去维护所有Sequence和ConsumerInfo的、EventHandler和ConsumerInfo的映射关系

/**
 * Provides a repository mechanism to associate {@link EventHandler}s with {@link EventProcessor}s
 *
 * @param  the type of the {@link EventHandler}
 */
class ConsumerRepository implements Iterable
{
    private final Map, EventProcessorInfo> eventProcessorInfoByEventHandler =
        new IdentityHashMap<>();
    private final Map eventProcessorInfoBySequence =
        new IdentityHashMap<>();
    private final Collection consumerInfos = new ArrayList<>();

    public void add(
        final EventProcessor eventprocessor,
        final EventHandler handler,
        final SequenceBarrier barrier)
    {
        final EventProcessorInfo consumerInfo = new EventProcessorInfo<>(eventprocessor, handler, barrier);
        eventProcessorInfoByEventHandler.put(handler, consumerInfo);
        eventProcessorInfoBySequence.put(eventprocessor.getSequence(), consumerInfo);
        consumerInfos.add(consumerInfo);
    }

SequenceBarrier

BatchEventProcessor处理类中维护的 前置Handler的sequence

关键方法waitFor()获取可用的sequence的index 具体获取逻辑视不同的WaitStrategy而变化,默认的BlockingWaitStrategy逻辑是

ringBuffer的游标值小于 processor想用的sequence 则ReentrantLock.Condition进行阻塞,大于等于的话 则判断barrier的sequence是否大于等于想用的sequence,小于的话则自旋等待

具体实现类ProcessingSequenceBarrier

/**
 * {@link SequenceBarrier} handed out for gating {@link EventProcessor}s on a cursor sequence and optional dependent {@link EventProcessor}(s),
 * using the given WaitStrategy.
 */
final class ProcessingSequenceBarrier implements SequenceBarrier
{
    private final WaitStrategy waitStrategy;
    private final Sequence dependentSequence;
    private volatile boolean alerted = false;
    private final Sequence cursorSequence;
    private final Sequencer sequencer;

    ProcessingSequenceBarrier(
        final Sequencer sequencer,
        final WaitStrategy waitStrategy,
        final Sequence cursorSequence,
        final Sequence[] dependentSequences)
    {
        this.sequencer = sequencer;
        this.waitStrategy = waitStrategy;
        this.cursorSequence = cursorSequence;
        if (0 == dependentSequences.length)
        {
            dependentSequence = cursorSequence;
        }
        else
        {
            dependentSequence = new FixedSequenceGroup(dependentSequences);
        }
    }

    @Override
    public long waitFor(final long sequence)
        throws AlertException, InterruptedException, TimeoutException
    {
        checkAlert();

        long availableSequence = waitStrategy.waitFor(sequence, cursorSequence, dependentSequence, this);

        if (availableSequence < sequence)
        {
            return availableSequence;
        }

        return sequencer.getHighestPublishedSequence(sequence, availableSequence);
    }

 

EventHandlerGroup

涉及到消费者 消费顺序等操作时需要这个数据结构保持一些相关数据

同样持有ConsumerRepository数据结构 及 Sequence数组(前置消费者执行器的Sequence)

 

EventProcessor

消费任务执行器

BatchEventProcessor常用的消费者执行器,下面具体分析他的processEvents

private void processEvents()
    {
        T event = null;
        long nextSequence = sequence.get() + 1L;//当前消费者处理到的sequence

        while (true)
        {
            try
            {
                final long availableSequence = sequenceBarrier.waitFor(nextSequence);//获取前置消费者已消费到的sequence
                if (batchStartAware != null)//是否有批处理
                {
                    batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
                }

                while (nextSequence <= availableSequence)
                {
                    event = dataProvider.get(nextSequence);
                    eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);//消费者执行具体Handler进行消费
                    nextSequence++;
                }

                sequence.set(availableSequence);//设置已处理的位置
            }
            catch (final TimeoutException e)
            {
                notifyTimeout(sequence.get());
            }
            catch (final AlertException ex)
            {
                if (running.get() != RUNNING)
                {
                    break;
                }
            }
            catch (final Throwable ex)
            {
                exceptionHandler.handleEventException(ex, nextSequence, event);
                sequence.set(nextSequence);
                nextSequence++;
            }
        }
    }

具体waitFor里面可是大有文章,细看ProcessingSequenceBarrier.waitFor

    ProcessingSequenceBarrier(
        final Sequencer sequencer,
        final WaitStrategy waitStrategy,
        final Sequence cursorSequence,
        final Sequence[] dependentSequences)
    {
        this.sequencer = sequencer;
        this.waitStrategy = waitStrategy;
        this.cursorSequence = cursorSequence;
        if (0 == dependentSequences.length)
        {
            dependentSequence = cursorSequence;//如果dependentSequences长度为0则默认使用游标sequence,即RingBuffer的Sequencer所持有的Sequence,当前可用的数据节点位置
        }
        else
        {
            dependentSequence = new FixedSequenceGroup(dependentSequences);
        }
    }

    @Override
    public long waitFor(final long sequence)
        throws AlertException, InterruptedException, TimeoutException
    {
        checkAlert();

        long availableSequence = waitStrategy.waitFor(sequence, cursorSequence, dependentSequence, this);//根据不同的等待策略 获取可靠的sequence

        if (availableSequence < sequence)
        {
            return availableSequence;
        }
        //如果availableSequence>= sequence 则获取最最高位的ring buffer已经发布的sequence
        return sequencer.getHighestPublishedSequence(sequence, availableSequence);
    }

 

WaitStrategy

BlockingWaitStrategy

游标小于目标sequence则加锁进行阻塞等待

/**
 * Blocking strategy that uses a lock and condition variable for {@link EventProcessor}s waiting on a barrier.
 * 

* This strategy can be used when throughput and low-latency are not as important as CPU resource. */ public final class BlockingWaitStrategy implements WaitStrategy { private final Lock lock = new ReentrantLock(); private final Condition processorNotifyCondition = lock.newCondition(); @Override public long waitFor(long sequence, Sequence cursorSequence, Sequence dependentSequence, SequenceBarrier barrier) throws AlertException, InterruptedException { long availableSequence; if (cursorSequence.get() < sequence) { lock.lock(); try { while (cursorSequence.get() < sequence) {//ring buffer 发布的sequence小于nextSequence 则阻塞,释放CPU资源 barrier.checkAlert(); processorNotifyCondition.await(); } } finally { lock.unlock(); } } //前置消费者位置小于nextSequence 则自旋等待 //多个前置消费者默认取最小的sequence,具体看FixSequenceGroup while ((availableSequence = dependentSequence.get()) < sequence) { barrier.checkAlert(); ThreadHints.onSpinWait(); } return availableSequence; }

BusySpinWaitStrategy

如果游标小于目标sequence则自旋

/**
 * Busy Spin strategy that uses a busy spin loop for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier.
 * 

* This strategy will use CPU resource to avoid syscalls which can introduce latency jitter. It is best * used when threads can be bound to specific CPU cores. */ public final class BusySpinWaitStrategy implements WaitStrategy { @Override public long waitFor( final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) throws AlertException, InterruptedException { long availableSequence; while ((availableSequence = dependentSequence.get()) < sequence) { barrier.checkAlert(); ThreadHints.onSpinWait(); } return availableSequence; }

LiteBlockingWaitStrategy 

这个策略有点没懂,哪里会提升性能

/**
 * Variation of the {@link BlockingWaitStrategy} that attempts to elide conditional wake-ups when
 * the lock is uncontended.  Shows performance improvements on microbenchmarks.  However this
 * wait strategy should be considered experimental as I have not full proved the correctness of
 * the lock elision code.
 */
public final class LiteBlockingWaitStrategy implements WaitStrategy
{
    private final Lock lock = new ReentrantLock();
    private final Condition processorNotifyCondition = lock.newCondition();
    private final AtomicBoolean signalNeeded = new AtomicBoolean(false);

    @Override
    public long waitFor(long sequence, Sequence cursorSequence, Sequence dependentSequence, SequenceBarrier barrier)
        throws AlertException, InterruptedException
    {
        long availableSequence;
        if (cursorSequence.get() < sequence)
        {
            lock.lock();

            try
            {
                do
                {
                    signalNeeded.getAndSet(true);

                    if (cursorSequence.get() >= sequence)
                    {
                        break;
                    }

                    barrier.checkAlert();
                    processorNotifyCondition.await();
                }
                while (cursorSequence.get() < sequence);
            }
            finally
            {
                lock.unlock();
            }
        }

        while ((availableSequence = dependentSequence.get()) < sequence)
        {
            barrier.checkAlert();
            ThreadHints.onSpinWait();
        }

        return availableSequence;
    }

TimeoutBlockingWaitStrategy

如果游标小于目标sequence则进行定时阻塞等待,如果超时则抛异常

如果未超时被唤醒则重新判断游标是否小于目标sequence

public class TimeoutBlockingWaitStrategy implements WaitStrategy
{
    private final Lock lock = new ReentrantLock();
    private final Condition processorNotifyCondition = lock.newCondition();
    private final long timeoutInNanos;

    public TimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units)
    {
        timeoutInNanos = units.toNanos(timeout);
    }

    @Override
    public long waitFor(
        final long sequence,
        final Sequence cursorSequence,
        final Sequence dependentSequence,
        final SequenceBarrier barrier)
        throws AlertException, InterruptedException, TimeoutException
    {
        long nanos = timeoutInNanos;

        long availableSequence;
        if (cursorSequence.get() < sequence)
        {
            lock.lock();
            try
            {
                while (cursorSequence.get() < sequence)
                {
                    barrier.checkAlert();
                    nanos = processorNotifyCondition.awaitNanos(nanos);
                    if (nanos <= 0)
                    {
                        throw TimeoutException.INSTANCE;
                    }
                }
            }
            finally
            {
                lock.unlock();
            }
        }

        while ((availableSequence = dependentSequence.get()) < sequence)
        {
            barrier.checkAlert();
        }

        return availableSequence;
    }

LiteTimeoutBlockingWaitStrategy

/**
 * Variation of the {@link TimeoutBlockingWaitStrategy} that attempts to elide conditional wake-ups
 * when the lock is uncontended.
 */
public class LiteTimeoutBlockingWaitStrategy implements WaitStrategy
{
    private final Lock lock = new ReentrantLock();
    private final Condition processorNotifyCondition = lock.newCondition();
    private final AtomicBoolean signalNeeded = new AtomicBoolean(false);
    private final long timeoutInNanos;

    public LiteTimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units)
    {
        timeoutInNanos = units.toNanos(timeout);
    }

    @Override
    public long waitFor(
        final long sequence,
        final Sequence cursorSequence,
        final Sequence dependentSequence,
        final SequenceBarrier barrier)
        throws AlertException, InterruptedException, TimeoutException
    {
        long nanos = timeoutInNanos;

        long availableSequence;
        if (cursorSequence.get() < sequence)
        {
            lock.lock();
            try
            {
                while (cursorSequence.get() < sequence)
                {
                    signalNeeded.getAndSet(true);

                    barrier.checkAlert();
                    nanos = processorNotifyCondition.awaitNanos(nanos);
                    if (nanos <= 0)
                    {
                        throw TimeoutException.INSTANCE;
                    }
                }
            }
            finally
            {
                lock.unlock();
            }
        }

        while ((availableSequence = dependentSequence.get()) < sequence)
        {
            barrier.checkAlert();
        }

        return availableSequence;
    }

 

PhasedBackoffWaitStrategy

如果目标游标大于依赖的sequence,则进行自旋,默认自旋10000次,如果达到10000次,则记录开始自旋时间,重新进行自旋,

自旋结束之后,自旋时间超过设置的退让CPU时间上线,则调用预先设置的备用WaitStrategy进行waitFor操作,否则如果超过自旋时间上线,则退让CPU

/**
 * 

Phased wait strategy for waiting {@link EventProcessor}s on a barrier.

* *

This strategy can be used when throughput and low-latency are not as important as CPU resource. * Spins, then yields, then waits using the configured fallback WaitStrategy.

*/ public final class PhasedBackoffWaitStrategy implements WaitStrategy { private static final int SPIN_TRIES = 10000; private final long spinTimeoutNanos; private final long yieldTimeoutNanos; private final WaitStrategy fallbackStrategy; public PhasedBackoffWaitStrategy( long spinTimeout, long yieldTimeout, TimeUnit units, WaitStrategy fallbackStrategy) { this.spinTimeoutNanos = units.toNanos(spinTimeout); this.yieldTimeoutNanos = spinTimeoutNanos + units.toNanos(yieldTimeout); this.fallbackStrategy = fallbackStrategy; } /** * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link BlockingWaitStrategy} * * @param spinTimeout The maximum time in to busy spin for. * @param yieldTimeout The maximum time in to yield for. * @param units Time units used for the timeout values. * @return The constructed wait strategy. */ public static PhasedBackoffWaitStrategy withLock( long spinTimeout, long yieldTimeout, TimeUnit units) { return new PhasedBackoffWaitStrategy( spinTimeout, yieldTimeout, units, new BlockingWaitStrategy()); } /** * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link LiteBlockingWaitStrategy} * * @param spinTimeout The maximum time in to busy spin for. * @param yieldTimeout The maximum time in to yield for. * @param units Time units used for the timeout values. * @return The constructed wait strategy. */ public static PhasedBackoffWaitStrategy withLiteLock( long spinTimeout, long yieldTimeout, TimeUnit units) { return new PhasedBackoffWaitStrategy( spinTimeout, yieldTimeout, units, new LiteBlockingWaitStrategy()); } /** * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link SleepingWaitStrategy} * * @param spinTimeout The maximum time in to busy spin for. * @param yieldTimeout The maximum time in to yield for. * @param units Time units used for the timeout values. * @return The constructed wait strategy. */ public static PhasedBackoffWaitStrategy withSleep( long spinTimeout, long yieldTimeout, TimeUnit units) { return new PhasedBackoffWaitStrategy( spinTimeout, yieldTimeout, units, new SleepingWaitStrategy(0)); } @Override public long waitFor(long sequence, Sequence cursor, Sequence dependentSequence, SequenceBarrier barrier) throws AlertException, InterruptedException, TimeoutException { long availableSequence; long startTime = 0; int counter = SPIN_TRIES; do { if ((availableSequence = dependentSequence.get()) >= sequence) { return availableSequence; } if (0 == --counter) { if (0 == startTime) { startTime = System.nanoTime(); } else { long timeDelta = System.nanoTime() - startTime; if (timeDelta > yieldTimeoutNanos)//超时时间超过退让超时时间,则切换waitStrategy { return fallbackStrategy.waitFor(sequence, cursor, dependentSequence, barrier); } else if (timeDelta > spinTimeoutNanos) { Thread.yield(); } } counter = SPIN_TRIES; } } while (true); } @Override public void signalAllWhenBlocking() { fallbackStrategy.signalAllWhenBlocking(); } }

 

SleepingWaitStrategy

如果目标sequence大于依赖的sequence最小值,则判断重试次数大于100,则进行自旋,大于0则进行退让CPU,小于等于0则进行定时阻塞

/**
 * Sleeping strategy that initially spins, then uses a Thread.yield(), and
 * eventually sleep (LockSupport.parkNanos(n)) for the minimum
 * number of nanos the OS and JVM will allow while the
 * {@link com.lmax.disruptor.EventProcessor}s are waiting on a barrier.
 * 

* This strategy is a good compromise between performance and CPU resource. * Latency spikes can occur after quiet periods. It will also reduce the impact * on the producing thread as it will not need signal any conditional variables * to wake up the event handling thread. */ public final class SleepingWaitStrategy implements WaitStrategy { private static final int DEFAULT_RETRIES = 200; private static final long DEFAULT_SLEEP = 100; private final int retries; private final long sleepTimeNs; public SleepingWaitStrategy() { this(DEFAULT_RETRIES, DEFAULT_SLEEP); } public SleepingWaitStrategy(int retries) { this(retries, DEFAULT_SLEEP); } public SleepingWaitStrategy(int retries, long sleepTimeNs) { this.retries = retries; this.sleepTimeNs = sleepTimeNs; } @Override public long waitFor( final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) throws AlertException { long availableSequence; int counter = retries; while ((availableSequence = dependentSequence.get()) < sequence) { counter = applyWaitMethod(barrier, counter); } return availableSequence; } @Override public void signalAllWhenBlocking() { } private int applyWaitMethod(final SequenceBarrier barrier, int counter) throws AlertException { barrier.checkAlert(); if (counter > 100) { --counter; } else if (counter > 0) { --counter; Thread.yield();//>0的时候优先让出CPU资源 } else { LockSupport.parkNanos(sleepTimeNs);//循环次数结束之后 进行睡眠一段时间 } return counter; }

 

YieldingWaitStrategy

目标sequence大于等于依赖的sequence最小值,则进行自旋,自旋次数到达后进行退让CPU

/**
 * Yielding strategy that uses a Thread.yield() for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier
 * after an initially spinning.
 * 

* This strategy will use 100% CPU, but will more readily give up the CPU than a busy spin strategy if other threads * require CPU resource. */ public final class YieldingWaitStrategy implements WaitStrategy { private static final int SPIN_TRIES = 100; @Override public long waitFor( final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) throws AlertException, InterruptedException { long availableSequence; int counter = SPIN_TRIES; while ((availableSequence = dependentSequence.get()) < sequence) { counter = applyWaitMethod(barrier, counter); } return availableSequence; } @Override public void signalAllWhenBlocking() { } private int applyWaitMethod(final SequenceBarrier barrier, int counter) throws AlertException { barrier.checkAlert(); if (0 == counter) { Thread.yield(); } else { --counter; } return counter; } }

上面通篇大多都是关于消费者的,那生产者的sequence也有一些逻辑

先从多个生产者来看:

主要就是当前游标跟 消费者中消费最慢的游标做比较,是否可以重置内容

MultiProducerSequencer

    /**
     * @see Sequencer#next(int)
     */
    @Override
    public long next(int n)
    {
        if (n < 1)
        {
            throw new IllegalArgumentException("n must be > 0");
        }

        long current;
        long next;

        do
        {
            current = cursor.get();
            next = current + n;
            //超过RingBuffer一圈的位置
            //消费者的最小sequence只要大于wrapPoint,则说明当前wrapPoint位置是可以重置的
            long wrapPoint = next - bufferSize;
            //这里用了一个缓存,个人理解是为了提高生产者的生产性能而做的设计
            long cachedGatingSequence = gatingSequenceCache.get();

            if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current)
            {
                long gatingSequence = Util.getMinimumSequence(gatingSequences, current);

                if (wrapPoint > gatingSequence)
                {
                    LockSupport.parkNanos(1); // TODO, should we spin based on the wait strategy?
                    continue;
                }

                gatingSequenceCache.set(gatingSequence);
            }
            else if (cursor.compareAndSet(current, next))
            {
                break;
            }
        }
        while (true);

        return next;
    }

SingleProducerSequencer

    /**
     * @see Sequencer#next(int)
     */
    @Override
    public long next(int n)
    {
        if (n < 1)
        {
            throw new IllegalArgumentException("n must be > 0");
        }

        long nextValue = this.nextValue;

        long nextSequence = nextValue + n;
        long wrapPoint = nextSequence - bufferSize;
        long cachedGatingSequence = this.cachedValue;

        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue)
        {
            cursor.setVolatile(nextValue);  // StoreLoad fence

            long minSequence;
            while (wrapPoint > (minSequence = Util.getMinimumSequence(gatingSequences, nextValue)))
            {
                LockSupport.parkNanos(1L); // TODO: Use waitStrategy to spin?
            }

            this.cachedValue = minSequence;
        }

        this.nextValue = nextSequence;

        return nextSequence;
    }

额外的小技巧:

因为是环形数组,存在可能存在第一圈index的数据,消费者用第二圈的index去消费

public final class MultiProducerSequencer extends AbstractSequencer
{
    private static final Unsafe UNSAFE = Util.getUnsafe();
    private static final long BASE = UNSAFE.arrayBaseOffset(int[].class);
    private static final long SCALE = UNSAFE.arrayIndexScale(int[].class);

    private final Sequence gatingSequenceCache = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);

    // availableBuffer tracks the state of each ringbuffer slot
    // see below for more details on the approach
    private final int[] availableBuffer;
    private final int indexMask;
    private final int indexShift;

    /**
     * Construct a Sequencer with the selected wait strategy and buffer size.
     *
     * @param bufferSize   the size of the buffer that this will sequence over.
     * @param waitStrategy for those waiting on sequences.
     */
    public MultiProducerSequencer(int bufferSize, final WaitStrategy waitStrategy)
    {
        super(bufferSize, waitStrategy);
        availableBuffer = new int[bufferSize];
        indexMask = bufferSize - 1;
        indexShift = Util.log2(bufferSize);
        initialiseAvailableBuffer();
    }



    private void initialiseAvailableBuffer()
    {
        for (int i = availableBuffer.length - 1; i != 0; i--)
        {
            setAvailableBufferValue(i, -1);
        }

        setAvailableBufferValue(0, -1);
    }

    private void setAvailable(final long sequence)
    {
        setAvailableBufferValue(calculateIndex(sequence), calculateAvailabilityFlag(sequence));
    }

    private void setAvailableBufferValue(int index, int flag)
    {
        long bufferAddress = (index * SCALE) + BASE;
        UNSAFE.putOrderedInt(availableBuffer, bufferAddress, flag);
    }

    /**
     * @see Sequencer#isAvailable(long)
     */
    @Override
    public boolean isAvailable(long sequence)
    {
        int index = calculateIndex(sequence);
        int flag = calculateAvailabilityFlag(sequence);
        long bufferAddress = (index * SCALE) + BASE;
        return UNSAFE.getIntVolatile(availableBuffer, bufferAddress) == flag;
    }

    //以buffer的size为单位 进行过滤
    private int calculateAvailabilityFlag(final long sequence)
    {
        return (int) (sequence >>> indexShift);
    }

    private int calculateIndex(final long sequence)
    {
        return ((int) sequence) & indexMask;
    }
}

 

总结

Disruptor框架里面最核心的就是Sequence,Sequence贯穿了所有的处理类和过渡类,里面的设计也避免了伪共享的问题,加上Ring Buffer中采用数组方式维护节点,并且定位节点采用了位运算取余,再加上缓存行预读操作,并且每个消费者自己维护自己的Sequence达到了内存栅栏的作用,而且整个框架尽量避免用到锁大部分都是CAS操作,让整个Disruptor框架性能显著提升

 

你可能感兴趣的:(Disruptor 源码解析)