disruptor源码阅读与分析---RingBuffer与Sequence

首先,我们还是编写一个测试例子吧,根据测试例子去分析代码更为直观:

public static void main(String[] args){
        EventFactory<EventObject> myEventFactory = new EventObjectFactory();//1
        ThreadFactory threadFactory = new StubThreadFactory();//2
        int ringBufferSize = 4;//3

        Disruptor<EventObject> disruptor = new Disruptor<EventObject>(myEventFactory,ringBufferSize,threadFactory, ProducerType.SINGLE,new BlockingWaitStrategy());//4
        EventHandler<EventObject> b = new ConsumerB();//5
        EventHandler<EventObject> c = new ConsumerC();//6
        EventHandler<EventObject> d = new ConsumerD();//7

        SequenceBarrier sequenceBarrier = disruptor.handleEventsWith(b,c).asSequenceBarrier();//8
        BatchEventProcessor processord = new BatchEventProcessor(disruptor.getRingBuffer(),sequenceBarrier,d);//9
        disruptor.handleEventsWith(processord);//10
        RingBuffer<EventObject> ringBuffer = disruptor.start();//11
        for(int i=0; i<10; i++) {//12
            long sequence = ringBuffer.next();//13
            try {
                EventObject myEvent = ringBuffer.get(sequence);//14
                myEvent.setValue(i);//15
            } finally {
                ringBuffer.publish(sequence);//16
            }
            SingleProducerSequencer singleProducerSequencer = (SingleProducerSequencer)(disruptor.getRingBuffer().getSequencer());
            System.out.println("producer:"+singleProducerSequencer.getProducerSequence()+"---consumer:"+singleProducerSequencer.getGatingSequences());
            try{
                Thread.sleep(100);
            }catch (Exception e){
            }
        }
        disruptor.shutdown();
    }

我们的disruptor版本为3.3.5,它是基于事件来进行处理任务的,下面我们逐行分析上面的代码,

第1行,EventFactory用于产生EventObject实例,是Disruptor构造函数的一个入参

第2行,threadFactory用于disruptor构造函数

第3行,ringbuffer大小

第4行,disruptor构造函数,

public Disruptor(
            final EventFactory<T> eventFactory,
            final int ringBufferSize,
            final ThreadFactory threadFactory,
            final ProducerType producerType,
            final WaitStrategy waitStrategy)
    {
        this(
            RingBuffer.create(producerType, eventFactory, ringBufferSize, waitStrategy),
            new BasicExecutor(threadFactory));
    }
    private Disruptor(final RingBuffer<T> ringBuffer, final Executor executor)
    {
        this.ringBuffer = ringBuffer;
        this.executor = executor;
    }

这里我们主要看下RingBuffer是如何创建的,这里我们的例子是模拟单个生产者的情况,所以看下单生产者下RingBuffer如何创建的
public static <E> RingBuffer<E> createSingleProducer(
        EventFactory<E> factory,
        int bufferSize,
        WaitStrategy waitStrategy)
    {
        SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);

        return new RingBuffer<E>(factory, sequencer);
    }

首先看下SingleProducerSequener,构造函数的入参有两个,最终构造函数会进入到AbstractSequencer的构造器上。AbstractSequencer是一个抽象类,这里我们重点看下其成员,
private static final AtomicReferenceFieldUpdater<AbstractSequencer, Sequence[]> SEQUENCE_UPDATER =
        AtomicReferenceFieldUpdater.newUpdater(AbstractSequencer.class, Sequence[].class, "gatingSequences");

    protected final int bufferSize;
    protected final WaitStrategy waitStrategy;
    protected final Sequence cursor = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);//代表着生产者对应的Sequence,初始的时候为-1,放入一个元素有这个值为0
    protected volatile Sequence[] gatingSequences = new Sequence[0];//代表着消费者对应的Sequence,有多少个消费者就有多少个对应的Sequence

可以看到一个SingleProducerSequencer里面包含了cursor和gatingSequences,我理解cursor就是生产者生产的元素该放入到哪个位置,gatingSequences就表示消费者消费到哪个位置,SEQUENCE_UPDATER用于对gatingSequences进行原子更新,这几个成员非常重要,可以在下文中看到其具体用处.这里我们需要看下Sequence类究竟长啥样:
class LhsPadding
{
    protected long p1, p2, p3, p4, p5, p6, p7;
}

class Value extends LhsPadding
{
    protected volatile long value;
}

class RhsPadding extends Value
{
    protected long p9, p10, p11, p12, p13, p14, p15;
}
public class Sequence extends RhsPadding
{
    static final long INITIAL_VALUE = -1L;
    private static final Unsafe UNSAFE;
    private static final long VALUE_OFFSET;

    static
    {
        UNSAFE = Util.getUnsafe();
        try
        {
            VALUE_OFFSET = UNSAFE.objectFieldOffset(Value.class.getDeclaredField("value"));
        }
        catch (final Exception e)
        {
            throw new RuntimeException(e);
        }
    }
}
这里在Value字段前后也做了填充,也是为了处理伪共享问题,其他的相关set操作都是使用的Unsafe类.

接下来我们再看下这个构造函数中干了啥,

public AbstractSequencer(int bufferSize, WaitStrategy waitStrategy)
    {
        if (bufferSize < 1)
        {
            throw new IllegalArgumentException("bufferSize must not be less than 1");
        }
        if (Integer.bitCount(bufferSize) != 1)
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        this.bufferSize = bufferSize;
        this.waitStrategy = waitStrategy;
    }

可以看到bufferSize要求是2的次方,为什么要有这个限制呢?这是因为普通的取余操作是比较耗性能的,限制为2的次方后,可以通过按位操作达到同样的效果.至此,SingleProducerSequencer的构造函数我们看完了,接下来看下RingBuffer的构造函数,最终是调用RingBufferFields的构造函数
RingBufferFields(
        EventFactory<E> 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)
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        this.indexMask = bufferSize - 1;
        /**
         * 申请的数组 entries 实际大小为 bufferSize + 2 * BUFFER_PAD,BUFFER_PAD 个数组元素占用 128 字节,也就是说在数组前后各加了 128 字节的填充,这主要是为了防止伪共享。
         */
        this.entries = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];
        fill(eventFactory);
    }
private void fill(EventFactory<E> eventFactory)
    {
        for (int i = 0; i < bufferSize; i++)
        {
            entries[BUFFER_PAD + i] = eventFactory.newInstance();
        }
    }

这里可以看到entries是一个数组,看上面的注释解释了为啥大小是bufferSize+2*BUFFER_PAD,所以实际使用中,entries[32...63]才是被EventObject填充过。

第5-7行实例化了三个消费者

第8行,首先看下handleEventWith这个方法

public EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)
    {
        return createEventProcessors(new Sequence[0], handlers);
    }
EventHandlerGroup<T> createEventProcessors(
        final Sequence[] barrierSequences,
        final EventHandler<? super T>[] eventHandlers)
    {
        checkNotStarted();

        final Sequence[] processorSequences = new Sequence[eventHandlers.length];
        final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);

        for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)
        {
            final EventHandler<? super T> eventHandler = eventHandlers[i];

            final BatchEventProcessor<T> batchEventProcessor =
                new BatchEventProcessor<T>(ringBuffer, barrier, eventHandler);

            if (exceptionHandler != null)
            {
                batchEventProcessor.setExceptionHandler(exceptionHandler);
            }

            consumerRepository.add(batchEventProcessor, eventHandler, barrier);
            processorSequences[i] = batchEventProcessor.getSequence();
        }

        if (processorSequences.length > 0)
        {
            ringBuffer.addGatingSequences(processorSequences);
            for (final Sequence barrierSequence : barrierSequences)
            {
                ringBuffer.removeGatingSequence(barrierSequence);
            }
            consumerRepository.unMarkEventProcessorsAsEndOfChain(barrierSequences);
        }

        return new EventHandlerGroup<T>(this, consumerRepository, processorSequences);
    }

上面的代码我们主要关注几行重要的代码:

final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences),注意这里的barrierSequences是个空数组,实现如下:

public SequenceBarrier newBarrier(Sequence... sequencesToTrack)
    {
        return sequencer.newBarrier(sequencesToTrack);//这里的sequencer就是前面实例化SingleProducerSequencer的一个对象
    }
public ProcessingSequenceBarrier(
        final Sequencer sequencer,
        final WaitStrategy waitStrategy,
        final Sequence cursorSequence,
        final Sequence[] dependentSequences)
    {
        this.sequencer = sequencer;//SingleProducerSequencer
        this.waitStrategy = waitStrategy;
        this.cursorSequence = cursorSequence;//生产者对应的Sequence
        if (0 == dependentSequences.length)
        {
            dependentSequence = cursorSequence;//与生产者相同的sequence
        }
        else
        {
            dependentSequence = new FixedSequenceGroup(dependentSequences);//被依赖的sequence,
        }
    }

SequenceBarrier其实就是一个ProcessingSequenceBarrier实例,可以看到此时的dependentSequence就是生产者的sequence,即生产者一旦生产了数据,立马就可以进行消费。

final BatchEventProcessor<T> batchEventProcessor = new BatchEventProcessor<T>(ringBuffer, barrier, eventHandler),我们来看下这个构造函数:

//成员变量
private final AtomicBoolean running = new AtomicBoolean(false);
    private ExceptionHandler<? super T> exceptionHandler = new FatalExceptionHandler();
    private final DataProvider<T> dataProvider;
    private final SequenceBarrier sequenceBarrier;
    private final EventHandler<? super T> eventHandler;
    private final Sequence sequence = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);//消费者初始化的Sequence
    private final TimeoutHandler timeoutHandler;
//构造函数
public BatchEventProcessor(
        final DataProvider<T> dataProvider,//就是我们的RingBuffer
        final SequenceBarrier sequenceBarrier,//刚产生的ProcessingSequenceBarrier
        final EventHandler<? super T> eventHandler)
    {
        this.dataProvider = dataProvider;//
        this.sequenceBarrier = sequenceBarrier;
        this.eventHandler = eventHandler;

        if (eventHandler instanceof SequenceReportingEventHandler)
        {
            ((SequenceReportingEventHandler<?>) eventHandler).setSequenceCallback(sequence);
        }

        timeoutHandler = (eventHandler instanceof TimeoutHandler) ? (TimeoutHandler) eventHandler : null;
    }

从这里我们可以看到,每个消费者都持有一个Sequence。

ringBuffer.addGatingSequences(processorSequences),这里也是一个比较关键的地方,processorSequences保存了消费者的Sequence,我们来看下实现,

public void addGatingSequences(Sequence... gatingSequences)
    {
        sequencer.addGatingSequences(gatingSequences);//SingleProducerSequencer
    }
@Override
public final void addGatingSequences(Sequence... gatingSequences)
{
	SequenceGroups.addSequences(this, SEQUENCE_UPDATER, this, gatingSequences);
}

还记得上面所说的SEQUENCE_UPDATER吧,这里就用上了,接下来我们进入这个方法:
static <T> void addSequences(
        final T holder,
        final AtomicReferenceFieldUpdater<T, Sequence[]> updater,
        final Cursored cursor,
        final Sequence... sequencesToAdd)
    {
        long cursorSequence;
        Sequence[] updatedSequences;
        Sequence[] currentSequences;

        do
        {
            currentSequences = updater.get(holder);
            updatedSequences = copyOf(currentSequences, currentSequences.length + sequencesToAdd.length);
            cursorSequence = cursor.getCursor();

            int index = currentSequences.length;
            for (Sequence sequence : sequencesToAdd)
            {
                sequence.set(cursorSequence);
                updatedSequences[index++] = sequence;
            }
        }
        while (!updater.compareAndSet(holder, currentSequences, updatedSequences));

        cursorSequence = cursor.getCursor();
        for (Sequence sequence : sequencesToAdd)
        {
            sequence.set(cursorSequence);
        }
    }

它的作用其实就是将消费者的Sequence保存到对应的变量gatingSeqeuces这个数组中。

回到我们的测试程序,我们再看下asSequenceBarrier方法:

public SequenceBarrier asSequenceBarrier()
    {
        return disruptor.getRingBuffer().newBarrier(sequences);
    }

同样是调用RingBuffer的newBarrier方法,与之前不同的是这里有dependentSequence,即消费者使用这个barrier时,需要等到dependentSequence对一你个的消费者消费后才能消费。

第9行,新建了一个实际的消费处理者BatchEventProcessor,

第10行,参见上面的handleEventsWith函数,这里会将新的消费者的sequence保存到SingleProducerSequencer的gatingSequences中

第11行,启动消费者,其处理逻辑主要是在BatchEventProcessor的run方法中,

public void run()
    {
        if (!running.compareAndSet(false, true))//将running标志设置为true
        {
            throw new IllegalStateException("Thread is already running");
        }
        sequenceBarrier.clearAlert();//设置ProcessingSequenceBarrier.alerted=false

        notifyStart();//这里暂时没有用上

        T event = null;
        long nextSequence = sequence.get() + 1L;//这里的sequence是每个消费者所持有的,初始值为-1,这里的nextSequence就是下一个要消费的位置
        try
        {
            while (true)
            {
                try
                {
                    final long availableSequence = sequenceBarrier.waitFor(nextSequence);

                    while (nextSequence <= availableSequence)
                    {
                        event = dataProvider.get(nextSequence);
                        eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
                        nextSequence++;
                    }

                    sequence.set(availableSequence);
                }
                catch (final TimeoutException e)
                {
                    notifyTimeout(sequence.get());
                }
                catch (final AlertException ex)
                {
                    if (!running.get())
                    {
                        break;
                    }
                }
                catch (final Throwable ex)
                {
                    exceptionHandler.handleEventException(ex, nextSequence, event);
                    sequence.set(nextSequence);
                    nextSequence++;
                }
            }
        }
        finally
        {
            notifyShutdown();
            running.set(false);
        }
    }

这里我们首先看下final long availableSequence = sequenceBarrier.waitFor(nextSequence)这行,看下waitfor方法的实现:
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);
    }

这里,我们的等待策略是BlockingWaitStrategy,看下其waitfor的实现:
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)
                {
                    barrier.checkAlert();
                    processorNotifyCondition.await();
                }
            }
            finally
            {
                lock.unlock();
            }
        }

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

        return availableSequence;
    }
消费者启动后,生产者还没有生产数据,所以此时的cursorSequence的值为-1,而我们需要消费的位置为0,当生产者Sequence小于消费者的sequence时,此时会进入等待,当生产者有数据来时,会将其唤醒。当被唤醒后,还需要看下依赖的sequence是否消费过了,否则还是要等待。

接下来就是开始消费,这里我们需要看下RingBuffer的get方法,

protected final E elementAt(long sequence)
    {
        return (E) UNSAFE.getObject(entries, REF_ARRAY_BASE + ((sequence & indexMask) << REF_ELEMENT_SHIFT));
    }

这里的entries就是那个数组,REF_ARRAY_BASE就是实际元素的起始地址,这里我们可以看出RingBuffer底层本质上是一个循环数组(队列)!

接下来设置当前消费者消费到哪个位置了。再回到测试程序,我们看下生产者,

第13行,获取下一个位置,最终是调用SingleProducerSequencer.next方法:

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)))
            {
                waitStrategy.signalAllWhenBlocking();
                LockSupport.parkNanos(1L); // TODO: Use waitStrategy to spin?
            }

            this.cachedValue = minSequence;
        }

        this.nextValue = nextSequence;

        return nextSequence;
    }

这里我们的n为1,表示获取下一个位置。wrapPoint和cachedGatingSequence用于判断当前队列的状况,比如队列是否是满的。举个例子,我们的RingBuffer大小为4,所以第一圈结束后,这个cachedValue=3,第二圈结束后这个值为7,以此类推。当队列中没有空的位置给生产者时,会调用park方法将生产者阻塞1纳秒。

第16行,看下publish方法,

public void publish(long sequence)
    {
        cursor.set(sequence);
        waitStrategy.signalAllWhenBlocking();
    }

设置当前生产者的sequence,表示这个位置已经产生了元素,可以进行消费了,然后唤醒等待的消费者。

至此,相关的代码已分析完毕,我们来总结下:

1,RingBuffer和Sequence在实现上都是借助于juc并发工具CAS,LockSupport等以及内存操作Unsafe类来实现高效操作

2,RingBuffer本质上是一个循环队列,采用了防伪共享的操作,利用Sequence实现了无锁的高效访问,它持有生产者和消费者的sequence

3,disruptor把cpu的有关缓存行,伪共享,内存屏障等等体现的很好

4,生产者通过Sequencer的大部分功能来使用序列。

5,消费者者通过SequenceBarrier来使用序列

6,从gc上看,RingBuffer通过填充eventObject的方式(底层是个数组,实际要操作的成员在eventObject中),极大的避免了gc带来的性能影响,这点相对于链表实现有极大的优势。

7,并发编程网上也有disruptor的介绍,不过光看介绍是很难理解其原理的,还是得看源码


上面的情况是单个生产者多个消费者这种一对多的方式,实际使用中当然这种情况占了大多数,但也不排除多对多的方式,这种情况下大致与一对多这种方式相同,不同的是在生产者sequence上会产生竞争,这个竞争通过cas方式来实现的,具体的可对照着源代码看,这里就不再分析了。


猜你喜欢

转载自blog.csdn.net/chengzhang1989/article/details/80241038