disruptor笔记之七:等待策略

2021-09-17  本文已影响0人  程序员欣宸

欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

《disruptor笔记》系列链接

  1. 快速入门
  2. Disruptor类分析
  3. 环形队列的基础操作(不用Disruptor类)
  4. 事件消费知识点小结
  5. 事件消费实战
  6. 常见场景
  7. 等待策略
  8. 知识点补充(终篇)

本篇概览

本文是《disruptor笔记》的第七篇,咱们一起阅读源码,学习一个重要的知识点:等待策略,由于Disruptor的源码短小精干、简单易懂,因此本篇是个轻松愉快的源码学习之旅;

提前小结

如果您时间不充裕,可以通过以下提前小结的内容,对等待策略有个大体的认识:

  1. BlockingWaitStrategy:用了ReentrantLock的等待&&唤醒机制实现等待逻辑,是默认策略,比较节省CPU
  2. BusySpinWaitStrategy:持续自旋,JDK9之下慎用(最好别用)
  3. DummyWaitStrategy:返回的Sequence值为0,正常环境是用不上的
  4. LiteBlockingWaitStrategy:基于BlockingWaitStrategy,在没有锁竞争的时候会省去唤醒操作,但是作者说测试不充分,不建议使用
  5. TimeoutBlockingWaitStrategy:带超时的等待,超时后会执行业务指定的处理逻辑
  6. LiteTimeoutBlockingWaitStrategy:基于TimeoutBlockingWaitStrategy,在没有锁竞争的时候会省去唤醒操作
  7. SleepingWaitStrategy:三段式,第一阶段自旋,第二阶段执行Thread.yield交出CPU,第三阶段睡眠执行时间,反复的的睡眠
  8. YieldingWaitStrategy:二段式,第一阶段自旋,第二阶段执行Thread.yield交出CPU
  9. PhasedBackoffWaitStrategy:四段式,第一阶段自旋指定次数,第二阶段自旋指定时间,第三阶段执行Thread.yield交出CPU,第四阶段调用成员变量的waitFor方法,这个成员变量可以被设置为BlockingWaitStrategy、LiteBlockingWaitStrategy、SleepingWaitStrategy这三个中的一个

关于等待策略

disruptor = new Disruptor<>(new OrderEventFactory(),
                BUFFER_SIZE,
                new CustomizableThreadFactory("event-handler-"));
    public static <E> RingBuffer<E> createMultiProducer(EventFactory<E> factory, int bufferSize)
    {
        return createMultiProducer(factory, bufferSize, new BlockingWaitStrategy());
    }
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
    @Override
    public void alert()
    {
        alerted = true;
        waitStrategy.signalAllWhenBlocking();
    }

BlockingWaitStrategy

在这里插入图片描述

BusySpinWaitStrategy(慎用)

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

    @Override
    public void signalAllWhenBlocking()
    {
    }
}
    public static void onSpinWait()
    {
        if (null != ON_SPIN_WAIT_METHOD_HANDLE)
        {
            try
            {
                ON_SPIN_WAIT_METHOD_HANDLE.invokeExact();
            }
            catch (final Throwable ignore)
            {
            }
        }
    }
static
    {
        final MethodHandles.Lookup lookup = MethodHandles.lookup();

        MethodHandle methodHandle = null;
        try
        {
            methodHandle = lookup.findStatic(Thread.class, "onSpinWait", methodType(void.class));
        }
        catch (final Exception ignore)
        {
        }

        ON_SPIN_WAIT_METHOD_HANDLE = methodHandle;
    }
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

DummyWaitStrategy

固定返回0,个人觉得这个策略在正常开发中用不上,因为环形队列可用位置始终是0的话,不论是生产还是消费都难以实现:

在这里插入图片描述

LiteBlockingWaitStrategy

在这里插入图片描述

TimeoutBlockingWaitStrategy

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

LiteTimeoutBlockingWaitStrategy

SleepingWaitStrategy

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

YieldingWaitStrategy

在这里插入图片描述

PhasedBackoffWaitStrategy

在这里插入图片描述
  1. 首先是自旋指定的次数,默认10000次;
  2. 自旋过后,开始带计时的自旋,执行的时长是spinTimeoutNanos的值;
  3. 执行时长达到spinTimeoutNanos的值后,开始执行<font color="blue">Thread.yield()</font>交出CPU资源,这个逻辑的执行时长是<font color="red">yieldTimeoutNanos-spinTimeoutNanos</font>;
  4. 执行时长达到<font color="red">yieldTimeoutNanos-spinTimeoutNanos</font>的值后,开始调用<font color="blue">fallbackStrategy.waitFor</font>,这个调用没有时间或者次数限制;
public static PhasedBackoffWaitStrategy withLock(
        long spinTimeout,
        long yieldTimeout,
        TimeUnit units)
    {
        return new PhasedBackoffWaitStrategy(
            spinTimeout, yieldTimeout,
            units, new BlockingWaitStrategy());
    }

public static PhasedBackoffWaitStrategy withLiteLock(
        long spinTimeout,
        long yieldTimeout,
        TimeUnit units)
    {
        return new PhasedBackoffWaitStrategy(
            spinTimeout, yieldTimeout,
            units, new LiteBlockingWaitStrategy());
    }

    public static PhasedBackoffWaitStrategy withSleep(
        long spinTimeout,
        long yieldTimeout,
        TimeUnit units)
    {
        return new PhasedBackoffWaitStrategy(
            spinTimeout, yieldTimeout,
            units, new SleepingWaitStrategy(0));
    }

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
https://github.com/zq2599/blog_demos

上一篇下一篇

猜你喜欢

热点阅读