当前位置:网站首页>Disruptor(一)Sequence

Disruptor(一)Sequence

2022-06-26 00:14:00 扶朕去网吧

在大扎了解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方法进行操作。

/**
 * Perform a compare and set operation on the sequence.
 *
 * @param expectedValue The expected current value.
 * @param newValue      The value to update to.
 * @return true if the operation succeeds, false otherwise.
 */
public boolean compareAndSet(final long expectedValue, final long newValue)
{
    return VALUE_FIELD.compareAndSet(this, expectedValue, newValue);
}

incrementAndGetaddAndGet

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

/**
 * Atomically add the supplied value.
 *
 * @param increment The value to add to the sequence.
 * @return The value after the increment.
 */
public long addAndGet(final long increment)
{
    return (long) VALUE_FIELD.getAndAdd(this, increment) + increment;
}

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

其他方法

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

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

3.缓存行填充

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

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

这一堆变量里面,有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

原网站

版权声明
本文为[扶朕去网吧]所创,转载请带上原文链接,感谢
https://blog.csdn.net/pxg943055021/article/details/125403317