• Disruptor(一)Sequence


    在大扎了解Disruptor的过程中,根据各个组件的的依赖程度,分别按照以下顺序来分篇说明每个组件的作用和用法,在下面的过程中,会以源码为主,手册为辅的方式,描述各个组件的作用以及原因。

    Sequence -> Sequencer-> Sequence Barrier -> Event -> Producer -> Ring Buffer -> Event Processor -> Wait Strategy -> Event Handler

    1. 前言

    并发sequence是用来进行ring buffer与event处理者情况进行跟踪的,支持大量CAS和顺序写的并发操作。

    并且通过对volatile字段周围填充的方式对伪共享问题更有效果,

    2. 方法(一致性保证)

    使用了一个VarHandle句柄来保证访问变量数据的并发操作,涉及到了sequence的3个方法:

    compareAndSet

    调用了VarHandle的compareAndSet方法进行操作。

    1. /**
    2.  * Perform a compare and set operation on the sequence.
    3.  *
    4.  * @param expectedValue The expected current value.
    5.  * @param newValue      The value to update to.
    6.  * @return true if the operation succeeds, false otherwise.
    7.  */
    8. public boolean compareAndSet(final long expectedValue, final long newValue)
    9. {
    10.     return VALUE_FIELD.compareAndSet(this, expectedValue, newValue);
    11. }

    incrementAndGetaddAndGet

    实际调用了VarHandle的getAndAdd方法进行操作,这里sequence的方法是add->get,而VarHandle的方法是get->add,所以在这个方法里面把调用VarHandler的值又加了个递增值。

    1. /**
    2.  * Atomically add the supplied value.
    3.  *
    4.  * @param increment The value to add to the sequence.
    5.  * @return The value after the increment.
    6.  */
    7. public long addAndGet(final long increment)
    8. {
    9.     return (long) VALUE_FIELD.getAndAdd(this, increment) + increment;
    10. }

    在VarHandle的这些操作方式里面,访问模式会覆盖掉定义时声明的模式,也就是说,如果你声明了一个反射字段句柄,但你使用了普通变量句柄来访问,会导致访问模式变为普通变量的模式。

    其他方法

    在其余的几个get(),set(),setVolatile()方法内均使用了VarHandle

    插入内存屏障的方法来保证数据的一致性。

    3.缓存行填充

    在Sequence中有一个内部类LhsPadding,里面声明了一堆变量,看起来是这样的:

    1. class LhsPadding
    2. {
    3.     protected byte
    4.         p10, p11, p12, p13, p14, p15, p16, p17,
    5.         p20, p21, p22, p23, p24, p25, p26, p27,
    6.         p30, p31, p32, p33, p34, p35, p36, p37,
    7.         p40, p41, p42, p43, p44, p45, p46, p47,
    8.         p50, p51, p52, p53, p54, p55, p56, p57,
    9.         p60, p61, p62, p63, p64, p65, p66, p67,
    10.         p70, p71, p72, p73, p74, p75, p76, p77;
    11. }

    这一堆变量里面,有8*7=56个byte,而在还有个内部类Value继承了LhsPadding,

    整体结构这样:

     

    并且还有个内部类RhsPadding又集成了Value,并且他也恰好有8*7=56个byte,而Value的数据类型是long,long为8个字节,所以这个Sequence对象一共有56+8+56=120个byte,而一般缓存行大小是64字节,无论如何分割,这个8个字节的byte都会与左侧填充或者右侧填充达到64个字节,从而避免伪共享问题。

                                            L                        Value                             R   

    56 byte8 byte56 byte
    56 byte8 byte56 byte

  • 相关阅读:
    论如何自研电动车控制器
    sql主从复制搭建
    RTSP/Onvif安防平台EasyNVR接入EasyNVS,出现报错“Login error, i/o deadline reached”的解决方法
    Windows系统的——终端命令行进入文件夹、打开程序或文件、返回路径、切换磁盘、查看路径包含的所有内容和配置环境变量操作
    SpringBoot中使用Thymeleaf
    【小余送书第二期】《MLOps工程实践:工具、技术与企业级应用》参与活动,即有机会中奖哦!!!祝各位铁铁们双节快乐!
    两个列表的最小索引总和
    你从浏览器输入一个URL到返回HTML界面给你这个流程发生了什么?【一文搞定吃透】
    将 mixamo 中的动画重定向到 UE 的小白人中
    在 Go 語言內使用 bytes.Buffer 注意事項
  • 原文地址:https://blog.csdn.net/pxg943055021/article/details/125403317