没有合适的资源?快使用搜索试试~ 我知道了~
Disruptor进阶.docx
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 152 浏览量
2021-09-14
16:09:32
上传
评论
收藏 108KB DOCX 举报
温馨提示
试读
18页
。。。
资源推荐
资源详情
资源评论
Disruptor 进阶
IntruductionDisruptor 是 Java实现的用于线程间通信的消
息组件。其核心是一个 Lock-free 的 Ringbuffer。我使用
BlockingQueue 与进 Disruptor 行了简单的对比测试,结果表
明使用 Disruptor 来进行线程间通信效率会提高将近一倍。而
LMAX 给出的数据是,使用 Disruptor 能够在一个线程里每
秒处理 6 百万订单。Disruptor 为什么会如此快呢?通过参考
Martin Fowler(Disruptor 的开发者之一)的技术博客和
Disruptor 的源代码,可以总结出以下四条原因:Lock vs
CASDisruptor 使用 CAS 而不是 Lock。关 于 CAS(compare and
swap)请参考 WIKIPEDIA 相关条目 Compare and swap。与大
部分并发队列使用的 Lock 相比,CAS 显然要快很多。CAS
是 CPU 级别的指令,更加轻量,不需要像 Lock 一样需要
OS 的支持,所以每次调用不需要 kernel entry,也不需要
context switch。当然,使用 CAS 的代价是 Disruptor 实现的
复杂程度也相对提高了。避免伪共享现代计算机体系架构在
各个层次都使用的 Cache 来提高效率,然而在多核体系结构
中,对 Cache 的不恰当使用极易造成伪共享,使性能下降。
关于伪共享请参考 WIKIPEDIA 相关条目 False sharing。为 了
避免伪共享带来的性能下降,Disruptor 对一切可能存在伪共
享的地方使用 Padding 将两个不想关的内存隔离到两个缓存
行上。可能存在伪共享的地方包括两个不相关的线程共享变
量之间,线程私有变量和线程共享变量之间等。下面分别举
例子说明。在 Disruptor 的实现中,有一个多线程共享的计数
组件 Sequence,对 Sequence 的操作可以说是整个 Disruptor
的核心,关于 Sequence,在下文介绍各个组件的时候还要详
细说明。这里主要说明它是怎样避免伪共享的。主要代码如
下:static final long INITIAL_VALUE = -1L;
private static final Unsafe UNSAFE;
private static final long VALUE_OFFSET;static
{
UNSAFE = Util.getUnsafe();
final int base = UNSAFE.arrayBaseOffset(long[].class);
final int scale = UNSAFE.arrayIndexScale(long[].class);
VALUE_OFFSET = base + (scale * 7);
}private final long[] paddedValue = new
long[15];. . . . . .public long get()
{
return UNSAFE.getLongVolatile(paddedValue,
VALUE_OFFSET);
}
Sequence 定义了一个长度为 15 的 long 类型数组,但仅使用
数组第八个元素进行计数,数组其他部分连同对象的头作为
padding 部分,保证在以 64byte 作为 Cache 缓存行大小的 CPU
中,计数元素(数组第八个元素)不会与其他变量存在于同
一个缓存行中。关于 Java 中对象在内存中具体怎样布局,可
以参考深入理解 Java 虚拟机:JVM 高级特性与最佳实践另
一个例子是关于线程私有变量的:private static class Padding
{
/** Set to -1 as sequence starting point */
public long nextValue = Sequence.INITIAL_VALUE,
cachedValue = Sequence.INITIAL_VALUE, p2, p3, p4, p5, p6,
p7;
}private final Padding pad = new Padding();
这段代码用在单生产者的应用场景中。在这种应用场景下,
这个计数器不需要是线程安全的,使用 Sequence 过于 heavy
了,但仍然需要通过 padding 将其与其他线程共享的变量隔
离开来。变量 p2 到 p7 以及对象头的作用就是这个。Linked
Queue vs Array RingbufferDisruptor选择使用Array Ringbuffer
来构造 lock-free 队列,而不是选择 Linked Queue。首先,数
组是预分配的,这样不仅避免了 Java GC 带来的运行开销,
而且因为在 ringbuffer 上进行的操作是顺序执行的,所以对
缓存来说更加友好,保证了缓存命中率。使用 Disruptor 的时
候,为了更好的利用 Ringbuffer 的这个优点,需要尽量将
Ringbuffer 的元素设计的可重用,生产者在生产消息或产生
剩余17页未读,继续阅读
资源评论
苦茶子12138
- 粉丝: 1w+
- 资源: 6万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功