在大扎了解Disruptor的过程中,根据各个组件的的依赖程度,分别按照以下顺序来分篇说明每个组件的作用和用法,在下面的过程中,会以源码为主,手册为辅的方式,描述各个组件的作用以及原因。
Sequence -> Sequencer-> Sequence Barrier -> Event -> Producer -> Ring Buffer -> Event Processor -> Wait Strategy -> Event Handler
并发sequence是用来进行ring buffer与event处理者情况进行跟踪的,支持大量CAS和顺序写的并发操作。
并且通过对volatile字段周围填充的方式对伪共享问题更有效果,
使用了一个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);
- }
incrementAndGet与addAndGet
实际调用了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
插入内存屏障的方法来保证数据的一致性。
在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 byte | 8 byte | 56 byte |
| 56 byte | 8 byte | 56 byte |