Java 并发编程实战
王宝令
资深架构师
72486 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

40 | 案例分析(三):高性能队列Disruptor

缓存行填充
对象循环利用
使用RingBuffer数据结构
无锁算法
避免伪共享
内存分配合理
避免伪共享的注解
发挥硬件的能力
优化并发性能
入队操作
缓存行填充
CPU缓存失效示意图
伪共享
Disruptor内部RingBuffer结构
ArrayBlockingQueue内部结构
程序的局部性原理
发布Event
注册事件处理器
构建Disruptor对象
自定义Event
性能优化原因
应用广泛
高性能的有界内存队列
总结
Disruptor中的无锁算法
如何避免“伪共享”
RingBuffer如何提升性能
Disruptor的使用
Disruptor
案例分析(三):高性能队列Disruptor
参考文章

该思维导图由 AI 生成,仅供参考

我们在《20 | 并发容器:都有哪些“坑”需要我们填?》介绍过 Java SDK 提供了 2 个有界队列:ArrayBlockingQueue 和 LinkedBlockingQueue,它们都是基于 ReentrantLock 实现的,在高并发场景下,锁的效率并不高,那有没有更好的替代品呢?有,今天我们就介绍一种性能更高的有界队列:Disruptor。
Disruptor 是一款高性能的有界内存队列,目前应用非常广泛,Log4j2、Spring Messaging、HBase、Storm 都用到了 Disruptor,那 Disruptor 的性能为什么这么高呢?Disruptor 项目团队曾经写过一篇论文,详细解释了其原因,可以总结为如下:
内存分配更加合理,使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;对象循环利用,避免频繁 GC。
能够避免伪共享,提升缓存利用率。
采用无锁算法,避免频繁加锁、解锁的性能消耗。
支持批量消费,消费者可以无锁方式消费多个消息。
其中,前三点涉及到的知识比较多,所以今天咱们重点讲解前三点,不过在详细介绍这些知识之前,我们先来聊聊 Disruptor 如何使用,好让你先对 Disruptor 有个感官的认识。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Disruptor是一款高性能的有界内存队列,相比于Java SDK提供的ArrayBlockingQueue和LinkedBlockingQueue,Disruptor在高并发场景下表现更出色。其性能优势主要体现在合理的内存分配、避免伪共享、无锁算法和支持批量消费等方面。Disruptor使用RingBuffer数据结构,通过一次性全部创建数组元素和循环利用对象,提升了缓存命中率并避免了频繁的GC。此外,Disruptor还充分考虑了程序的局部性原理,通过连续的内存地址和循环利用Event来提升性能。总的来说,Disruptor在高性能队列方面具有明显的优势,被广泛应用于Log4j2、Spring Messaging、HBase、Storm等项目中。 Disruptor在优化并发性能方面可谓是做到了极致,优化的思路大体是两个方面,一个是利用无锁算法避免锁的争用,另外一个则是将硬件(CPU)的性能发挥到极致。尤其是后者,在Java领域基本上属于经典之作了。 Disruptor提供了经典的实现,通过填充方式避免伪共享,这对于Java程序员来说是一个重要的优化技巧。文章还提到了Java 8中提供了避免伪共享的注解@sun.misc.Contended,但需要注意避免伪共享是以牺牲内存为代价的,具体使用时需要仔细斟酌。文章内容涉及了伪共享、CPU缓存失效、Disruptor中的无锁算法等技术细节,对于对性能优化感兴趣的读者来说,是一篇值得深入阅读的文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(48)

  • 最新
  • 精选
  • Juc
    希望老师解释下,为什么创建元素的时间离散会导致元素的内存地址不是连续的?这些元素不是存在数组中的吗?数组初始化不是已经连续分配内存了吗?

    作者回复: 数组连续,数组里只有引用,e1 e2这些对象的地址不连续

    2019-05-30
    2
    56
  • 冰激凌的眼泪
    前后56个字节保证了目标字段总是独占一个cache line,不受周围变量缓存失效的影响

    作者回复: 👍

    2019-07-03
    5
    23
  • 万历十五年
    单机提升性能不外乎是围绕CPU,内存和IO想办法。 CPU:  1.避免线程切换:单线程,对于多线程进行线程绑定,使用CAS无锁技术 2.利用CPU缓存,还有缓存填充,设计数据结构和算法 内存: 1.多级缓存:应用缓存,第三方缓存,系统缓存 2.数组优于链表 3.避免频繁内存碎片:利用池思想复用对象 解决IO产生的速度差: 1.多路复用 2.队列削峰 3.协程

    作者回复: ������������

    2020-12-20
    22
  • 惘 闻
    if (wrapPoint>cachedGatingSequence || cachedGatingSequence>current)这个位置的判断原本不明白,看了几遍总算是明白了. 环形队列,生产者从0生产 消费者从0消费. wrapPoint是指生产了一圈 又达到了 消费者消费的最小的位置 如果此时继续生产,那么消费最少的消费者还未消费的消息将会被生产者覆盖,所以此处要停止. 而 最小消费位置大于生产者当前生产位置的话,说明消费到了生产者还未生产消息的位置,所以等待消息的生产,要停止.

    作者回复: 👍🏻

    2020-08-26
    2
    17
  • xinglichea
    老师,感觉填充的模式不是很靠谱,程序的健壮性要强依赖于CPU的缓存行的实现,打个比如,如果以后CPU缓存行变成了128个字节,那企不要写Disruptor的实现源码,然后原来实现的代码仍然会有伪共享的问题!!!

    作者回复: 我觉得从官方提供注解这一行为来看,应该不至于不靠谱,不过java程序员都习惯于不关注硬件。

    2019-08-29
    5
  • 那月真美
    老师,数组内存地址连续,数组里面的引用对象怎么做到连续呢?它不是由生产者产生的吗?何时生产只能由生产者决定,初始化数组的时候怎么一次性初始化数组元素啊?

    作者回复: Disruptor 内部的 RingBuffer 也是用数组实现的,但是这个数组中的所有元素在初始化时是一次性全部创建的,所以这些元素的内存地址大概率是连续的。一次性全部创建,大概率事关键词。参考文中LongEvent的例子,生产用的是set方法,而不是add方法

    2020-09-16
    3
  • 张洋
    1.if (wrapPoint>cachedGatingSequence || cachedGatingSequence>current) 这点开始一直没看懂,之前写过环形队列,每次索引都会重置,就是一直在0-9之间,然后看了下RingBuffer 好像它的索引是一直累加的。这样就好懂多了。 2.关于ArrayBlockQueue 添加的对象是不连续的还是不太明白,数组初始化 不是在内存种开辟出一段连续的内存空间吗? 还是按照有的同学留言所说的,如果是引用对象不一定是连续的。

    作者回复: 数组里所有的对象的引用一定是连续的,但是对象不一定连续

    2020-12-29
    2
  • 神佑小鹿
    ArrayBlockingQueue 的入队和出队操作是用锁来保证互斥的,所以入队和出队不会同时发生。如果允许入队和出队同时发生,那就会导致线程 A 和线程 B 争用同一个缓存行,这样也会导致性能问题。 想问下加锁了就没有缓存干扰了吗!为啥?

    作者回复: 缓存导致的可见性问题靠的是HB规则,锁是靠HB规则解决缓存问题的

    2019-11-26
    2
    2
  • 码农Kevin亮
    老师,避免伪共享的逻辑有点困惑: 伪共享逻辑上就是没实现共享,而disruptor用行填充也是没实现共享。那么为什么避免伪共享就能提升性能呢?

    作者回复: 共享,指的是多个核能共享缓存,避免伪共享后,多个核是可以共享缓存的

    2019-06-02
    1
  • 全麦小面包
    老师,有个问题哈。Disruptor创建的event不是业务数据类,里面set的东西才是业务需要的。但set对象的创建还是离散的,难道set对象的引用,能和event一起缓存??java有这种机制吗?

    作者回复: 没有这种机制

    2022-07-26归属地:北京
收起评论
显示
设置
留言
48
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部