Disruptor学习笔记
前言
以前一直听说有Disruptor这个东西,都说性能很强大,所以这几天自己也看了一下。
下面是自己的学习笔记,另外推荐几篇自己看到写的比较好的博客:
Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案
Disruptor3.0的实现细节
DIsruptor的底层性能如此牛掰
- 数据结构层面:使用环形结构、数组、内存预加载
- 单线程写方式、内存屏障
- 消除伪共享(填充缓存行)
- 序号栅栏(
SequenceBarrier)配合使用来消除锁和CAS
高性能之道-数据结构-内存加载机制
- RingBuffer使用数组Object[] entries作为存储元素,如下图所示

高性能之道-内核-使用单线程写
- Disruptor的RingBuffer,之所以可以做到完全无锁,也是因为 ”单线程写“, 这是所有”前提的前提“。离开了这个前提条件,没有任何技术可以做到完全无锁
- Redis、Netty等等高性能技术框架的设计都是这个核心思想
高性能之道-系统内存优化-内存屏障
- 要正确的实现无锁,还需要另一个关键技术:内存屏障。
- 对应到Java语言,就是valotile变量与happens before语义。
- 内存屏障-Linux的smp_wmb()/smp_rmb()
高性能之道-系统缓存优化-消除伪共享
- 缓存系统中是以缓存行(cache line)为单位存储的
- 缓存行是2的整数幂个连续字节,一般为32-256个字节
- 最常见的缓存行大小是64个字节
- 当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行
- 就会无意中影响彼此的性能,这就是伪共享 -- 对应源码中的:
Sequence:
Disruptor核心-Sequence
- Sequence可以看成是一个AtomicLong,用于标识进度
- 还有另外一个目的就是防止不同Sequence之间CPU缓存伪共享(False Sharing)的问题-- 对应源码中的:
Sequence:
高性能之道-算法优化-序号栅栏机制
- 我们在生产者进行投递Event的时候,总会使用:long sequence = ringBuffer.next();
- Disruptor 3.0中,序号栅栏SequenceBarrier和序号Sequence搭配使用,协同和管理消费者与生产者的工作节奏,避免了锁和CAS的使用
- 在Disruptor3.0中,各个消费者和生产者持有自己的序号,这些序号的变化必须满足如下基本条件:-- 参见源码:
SingleProducerSequencer
a. 消费者的序号数值必须小于生产者序号数值;b. 消费者序号数值必须小于其前置(依赖关系)消费者的序号数值; c. 生产者序号数值不能大于消费者最小的序号数值以避免生产者速度过快,将还未来得及消费的消息覆盖
WatiStrategy等待策略
- Disruptor之所以可以说是高性能,其实也有一部分原因取决于它的等待策略的实现:WaitStrategy接口:
-- 查看源码BlockingWaitStrategy
-- 查看源码YieldingWaitStrategy

Disruptor核心-EventProcessor
- EventProcessor:主要时间循环,处理Disruptor中的Event,拥有消费者的Sequence
- 它有一个实现类是BatchEventProcessor,包含了event loop有效的实现,并且将回调到一个EventHandler接口的思想对象 -- 参见
BatchEventProcessor
源码解读
Disruptor:Disruptor的入口,主要封装了环形队列RingBuffer、消费者集合ConsumerRepository的引用;主要提供了获取环形队列、添加消费者、生产者向RingBuffer中添加事件(可以理解为生产者生产数据)的操作;
RingBuffer:Disruptor中队列具体的实现,底层封装了Object[]数组;在初始化时,会使用Event事件对数组进行填充,填充的大小就是bufferSize设置的值;此外,该对象内部还维护了Sequencer(序列生产器)具体的实现;
Sequencer:序列生产器,分别有MultiProducerSequencer(多生产者序列生产器) 和 SingleProducerSequencer(单生产者序列生产器)两个实现类。上面的例子中,使用的是SingleProducerSequencer;在Sequencer中,维护了消费者的Sequence(序列对象)和生产者自己的Sequence(序列对象);以及维护了生产者与消费者序列冲突时候的等待策略WaitStrategy;
Sequence:序列对象,内部维护了一个long型的value,这个序列指向了RingBuffer中Object[]数组具体的角标。生产者和消费者各自维护自己的Sequence;但都是指向RingBuffer的Object[]数组;
Wait Strategy:等待策略。当没有可消费的事件时,消费者根据特定的策略进行等待;当没有可生产的地方时,生产者根据特定的策略进行等待;
Event:事件对象,就是我们Ringbuffer中存在的数据,在Disruptor中用Event来定义数据,并不存在Event类,它只是一个定义;
EventProcessor:事件处理器,单独在一个线程内执行,判断消费者的序列和生产者序列关系,决定是否调用我们自定义的事件处理器,也就是是否可以进行消费;
EventHandler:事件处理器,由用户自定义实现,也就是最终的事件消费者,需要实现EventHandler接口;
RingBuffer:

Sequence:

这个里面缓存行的填充很经典,设计成前7后7 Long类型来填充,保证消除伪共享。
使用空间换时间,避免伪共享。Java8中使用@sun.misc.Contended 来消除伪共享,在运行时需要设置JVM启动参数:-XX:-RestrictContended
这里前7后7加上本身的Value值,总共是有15个Long元素,无论如何拆分,Value和预填充的Long型数据一定会处于单独的一个缓存行。
SingleProducerSequencer

这里就是用简单的if else判断,就避免了加锁,CAS的消耗,这里是使用序号栅栏,通过巧妙的算法+自旋操作来实现等待的操作。
解析如下图:

其中可以自己写代码去debug,创建ringBuffer长度为4,消费者阻塞在第0个元素的消费中。然后生产者再生产第5个元素的时候就会进行自旋等待。
BlockingWaitStrategy

BatchEventProcessor
waitFor 可以参考上面的BlockingWaitStrategy 的waitFor() 方法
Disruptor学习笔记的更多相关文章
- Disruptor学习笔记(一):基本原理和概念
一.Disruptor基本原理 在多线程开发中,我们常常遇到这样一种场景:一些线程接受用户请求,另外一些线程处理这些请求.比如日志处理中的日志输入和告警.这种典型的生产者消费者场景十分常见,而生产者消 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
随机推荐
- Immediate Decodability HDU1305
类似phonelist 一次ac 判断失败主要有两个要点 1. 是否包含了某段的结尾结点 说明某段被此段包含 2.此段的结尾结点是否为某段的痕迹 说明此段被包含 #include<bi ...
- X分钟速成Python3
参考博客:Python3 从入门到开车 (与以下代码无关) 源代码下载: learnpython3-cn.py Python是由吉多·范罗苏姆(Guido Van Rossum)在90年代早期设计. ...
- Java Web报错: GET http://localhost:8080/ 404 (Not Found)
eclipse正常启动tomcat,但是 访问http://localhost:8080 报404错误 搞笑的是我访问服务器中的其他网页也可以打开 报错如下: 解决: 如果这3项都已经变灰色,删除配置 ...
- [OpenCV-Python] OpenCV 中计算摄影学 部分 IX 对象检测 部分 X
部分 IX计算摄影学 OpenCV-Python 中文教程(搬运)目录 49 图像去噪目标 • 学习使用非局部平均值去噪算法去除图像中的噪音 • 学习函数 cv2.fastNlMeansDenoisi ...
- IdentityServer4-前后端分离之Vue(七)
前言 之前文章讲到如何使用Node.js+Express构建JavaScript客户端,实现前后端分离.本节将介绍如何使用Vue实现前后端分离,文中介绍Vue的知识比较基础,适合新手学习. 一.搭建V ...
- 一个基于C++11的定时器队列(timerfd,poll实现)
目录 前言 优点 test 源代码 @ 前言 最近小程序要用到定时器,找了一圈也没找到合适的,最后还是绕回来选择了muduo里面的TimerQueue,整理了下它的代码,独立了出来,因为实在懒得从头写 ...
- sql注入总结(一)--2018自我整理
SQL注入总结 前言: 本文和之后的总结都是进行总结,详细实现过程细节可能不会写出来~ 所有sql语句均是mysql数据库的,其他数据库可能有些函数不同,但是方法大致相同 0x00 SQL注入原理: ...
- 关于H5在移动端架构的优化设计总结
各大互联网公司采取的策略 一.百度移动前端首页 1. 对于首屏的静态文件css/js,在上线前全部编译直出到HTML文件中:整个首页的渲染只需要一次请求: 2.使用缓存:把不变的js/css/html ...
- supervisor 管理 celery
安装supervisor [root@ipv6-api ~]# pip3 install supervisor 生成配置文件 [root@ipv6-api ~]#echo_supervisord_c ...
- 4067: [Ctsc2015]gender 动态规划 网络流
国际惯例的题面:首先这题是缺少两个隐藏条件的:第一个是这k条链的起点和终点所在的层是对齐的,也就是说不会出现两条链错开的情况,且这张图恰好由n层组成:第二个就是任意一个点都包含在与链上的点直接或间接相 ...