本文的一些理解基于http://ifeve.com/?x=29&y=10&s=disruptor 一系列文章
disruptor 版本 3.4.2
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));
}//这样的设计应该就是解决伪共享,预读数组,求余操作优化
消费者信息 包含:消费者执行器、Handler以及前置SequenceBarrier
具体实现类
EventProcessInfo
class EventProcessorInfo implements ConsumerInfo
{
private final EventProcessor eventprocessor;
private final EventHandler super T> handler;
private final SequenceBarrier barrier;
private boolean endOfChain = true;
EventProcessorInfo(
final EventProcessor eventprocessor, final EventHandler super T> handler, final SequenceBarrier barrier)
{
this.eventprocessor = eventprocessor;
this.handler = handler;
this.barrier = barrier;
}
}
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 super T> handler,
final SequenceBarrier barrier)
{
final EventProcessorInfo consumerInfo = new EventProcessorInfo<>(eventprocessor, handler, barrier);
eventProcessorInfoByEventHandler.put(handler, consumerInfo);
eventProcessorInfoBySequence.put(eventprocessor.getSequence(), consumerInfo);
consumerInfos.add(consumerInfo);
}
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);
}
涉及到消费者 消费顺序等操作时需要这个数据结构保持一些相关数据
同样持有ConsumerRepository数据结构 及 Sequence数组(前置消费者执行器的Sequence)
消费任务执行器
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);
}
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框架性能显著提升