// com.lmax.disruptor.BatchEventProcessor#processEvents
private void processEvents()
{
T event = null;
/*
这里的sequence在com.lmax.disruptor.dsl.Disruptor#handleEventsWith(com.lmax.disruptor.EventProcessor...) 或者
com.lmax.disruptor.dsl.Disruptor#handleEventsWith(com.lmax.disruptor.EventHandler<? super T>...)方法初始化的时候
会做一份com.lmax.disruptor.EventProcessor数组的引用copy(最终内存地址依然是同一个),然后将此copy通过
com.lmax.disruptor.RingBuffer放到com.lmax.disruptor.AbstractSequencer中的gatingSequences数组中,至此消费者的消费进度更新间
接和生产者建立制约关系。
*/
long nextSequence = sequence.get() + 1L;
while (true)
{
try
{
// 根据当前batch线程中的消费进度标记nextSequence算出下一批可用序列号位置(最大)
final long availableSequence = sequenceBarrier.waitFor(nextSequence);
if (batchStartAware != null)
{
batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
}
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() != RUNNING)
{
break;
}
}
catch (final Throwable ex)
{
exceptionHandler.handleEventException(ex, nextSequence, event);
sequence.set(nextSequence);
nextSequence++;
}
}
}
// com.lmax.disruptor.ProcessingSequenceBarrier#waitFor
@Override
public long waitFor(final long sequence)
throws AlertException, InterruptedException, TimeoutException
{
checkAlert();
/*
这里的cursorSequence、dependentSequence引用指向生产者com.lmax.disruptor.AbstractSequencer中的cursor
*/
long availableSequence = waitStrategy.waitFor(sequence, cursorSequence, dependentSequence, this);
if (availableSequence < sequence)
{
return availableSequence;
}
return sequencer.getHighestPublishedSequence(sequence, availableSequence);
}
// com.lmax.disruptor.BlockingWaitStrategy#waitFor
@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)
{
barrier.checkAlert();
processorNotifyCondition.await();
}
}
finally
{
lock.unlock();
}
}
// 如果生产者进度小于当前消费者需要进度,则进行等待
while ((availableSequence = dependentSequence.get()) < sequence)
{
barrier.checkAlert();
ThreadHints.onSpinWait();
}
return availableSequence;
}
// com.lmax.disruptor.MultiProducerSequencer#getHighestPublishedSequence
@Override
public long getHighestPublishedSequence(long lowerBound, long availableSequence)
{
for (long sequence = lowerBound; sequence <= availableSequence; sequence++)
{
/*
循环逐个校验availableBuffer中是否可用,发现不可用则返回前一个位置(一定是可用的)
此步骤主要是为了防止多生产者并发生产导致取得的序列号是没有来得及发布的,所以以availableBuffer为准
生产者发布数据的时候,会同步更新availableBuffer中相应位置的值为calculateAvailabilityFlag(sequence)
*/
if (!isAvailable(sequence))
{
return sequence - 1;
}
}
return availableSequence;
}
/**
* com.lmax.disruptor.MultiProducerSequencer#isAvailable
*/
@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;
}
// com.lmax.disruptor.MultiProducerSequencer#calculateAvailabilityFlag
/*
生产者、消费者都会调用此算法,来进行相应位置的值认证。
*/
private int calculateAvailabilityFlag(final long sequence)
{
return (int) (sequence >>> indexShift);
}
/*******************************************************发布数据********************************************************************/
// com.lmax.disruptor.MultiProducerSequencer#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;
long wrapPoint = next - bufferSize;
long cachedGatingSequence = gatingSequenceCache.get();
/*
1. 当生产者进度超过消费者一圈
2. 所有消费者最小消费进度下标大于生产者下标current则进行自旋
*/
if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current)
{
/*
gatingSequences中保存了相应位置的消费者状态,是通过com.lmax.disruptor.BatchEventProcessor里面的sequence标记消费进度
此步骤在所有消费者进度数组和当前
*/
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);
}
/*
这里的crusor会一直递增,肯定会超过bufferSize,在后面publish时,通过&运算会重新计算出相应数组位置的下标。
消费者com.lmax.disruptor.ProcessingSequenceBarrier#waitFor会依赖此处cursor值进行等待
*/
else if (cursor.compareAndSet(current, next))
{
break;
}
}
while (true);
return next;
}
// com.lmax.disruptor.MultiProducerSequencer#setAvailable
/**
* The below methods work on the availableBuffer flag.
* <p>
* The prime reason is to avoid a shared sequence object between publisher threads.
* (Keeping single pointers tracking start and end would require coordination
* between the threads).
* <p>
* -- Firstly we have the constraint that the delta between the cursor and minimum
* gating sequence will never be larger than the buffer size (the code in
* next/tryNext in the Sequence takes care of that).
* -- Given that; take the sequence value and mask off the lower portion of the
* sequence as the index into the buffer (indexMask). (aka modulo operator)
* -- The upper portion of the sequence becomes the value to check for availability.
* ie: it tells us how many times around the ring buffer we've been (aka division)
* -- Because we can't wrap without the gating sequences moving forward (i.e. the
* minimum gating sequence is effectively our last available position in the
* buffer), when we have new data and successfully claimed a slot we can simply
* write over the top.
*/
private void setAvailable(final long sequence)
{
setAvailableBufferValue(calculateIndex(sequence), calculateAvailabilityFlag(sequence));
}
// com.lmax.disruptor.MultiProducerSequencer#calculateAvailabilityFlag
private int calculateAvailabilityFlag(final long sequence)
{
return (int) (sequence >>> indexShift);
}
private void setAvailableBufferValue(int index, int flag)
{
long bufferAddress = (index * SCALE) + BASE;
UNSAFE.putOrderedInt(availableBuffer, bufferAddress, flag);
}