Disruptor源码分析之其他功能

单生产者

SingleProducerSequencer单生产者类,nextValue代表当前的下标,nextSequence代表这次需要的下标,与多生产者类似,只是不需要循环重试,因为只有一个生产者产生数据,所以只需要一次判断就可以,没什么并发问题。


public long next(int n)
{
    if (n < 1 || n > bufferSize)
    {
        throw new IllegalArgumentException("n must be > 0 and < bufferSize");
    }

    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;
}

批量消费线程

每个消费线程消费所有的数据,eventHandler为业务消费实现接口,dataProvider是RingBuffer,sequenceBarrier则为统一定序器管理类。

public BatchEventProcessor(
    final DataProvider<T> dataProvider,
    final SequenceBarrier sequenceBarrier,
    final EventHandler<? super T> eventHandler)
{
    this.dataProvider = dataProvider;
    this.sequenceBarrier = sequenceBarrier;
    this.eventHandler = eventHandler;

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

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

每个执行线程如下,判断运行状态,发布通知事件,清除中断标志


public void run()
{
    if (running.compareAndSet(IDLE, RUNNING))
    {
        sequenceBarrier.clearAlert();

        notifyStart();
        try
        {
            if (running.get() == RUNNING)
            {
                processEvents();
            }
        }
        finally
        {
            notifyShutdown();
            running.set(IDLE);
        }
    }
    else
    {
        // This is a little bit of guess work.  The running state could of changed to HALTED by
        // this point.  However, Java does not have compareAndExchange which is the only way
        // to get it exactly correct.
        if (running.get() == RUNNING)
        {
            throw new IllegalStateException("Thread is already running");
        }
        else
        {
            earlyExit();
        }
    }
}

 

开始获取并处理任务,等待获取可用的下标,需要的下标小于可用下标时就开始从数组中获取数据,依次消费,最后把所有的可用下标消费完成后保存起来,以供下一次获取后续的下标数据。


private void processEvents()
{
    T event = null;
    long nextSequence = sequence.get() + 1L;

    while (true)
    {
        try
        {
            final long availableSequence = sequenceBarrier.waitFor(nextSequence);
            if (batchStartAware != null && availableSequence >= nextSequence)
            {
                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++;
        }
    }
}

等待策略

YieldingWaitStrategy

此策略将使用100%的CPU,但如果其他线程需要CPU资源,则比繁忙的自旋策略更容易放弃CPU。循环调用方法对100递减1并判断是否满足条件,如果不满足的就循环暂时释放cpu然后等待获取判断条件是否满足。

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;
}

private int applyWaitMethod(final SequenceBarrier barrier, int counter)
        throws AlertException
{
    barrier.checkAlert();

    if (0 == counter)
    {
        Thread.yield();
    }
    else
    {
        --counter;
    }

    return counter;
}

 

BusySpinWaitStrategy

此策略将使用CPU资源来避免可能导致延迟抖动的系统调用。当线程可以绑定到特定的CPU核心时,最好使用它。

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;
}

SleepingWaitStrategy

这个策略是性能和CPU资源之间的一个很好的折衷。延迟峰值可能在静默期之后出现。它还将减少对生成线程的影响,因为它不需要任何条件变量的信号来唤醒事件处理线程。


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;
}

private int applyWaitMethod(final SequenceBarrier barrier, int counter)
    throws AlertException
{
    barrier.checkAlert();

    if (counter > 100)
    {
        --counter;
    }
    else if (counter > 0)
    {
        --counter;
        Thread.yield();
    }
    else
    {
        LockSupport.parkNanos(sleepTimeNs);
    }

    return counter;
}

TimeoutBlockingWaitStrategy

当吞吐量和低延迟不如CPU资源重要时,可以使用此策略。

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

    long availableSequence;
    if (cursorSequence.get() < sequence)
    {
        synchronized (mutex)
        {
            while (cursorSequence.get() < sequence)
            {
                barrier.checkAlert();
                timeoutNanos = awaitNanos(mutex, timeoutNanos);
                if (timeoutNanos <= 0)
                {
                    throw TimeoutException.INSTANCE;
                }
            }
        }
    }

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

    return availableSequence;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值