欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

《disruptor笔记》系列链接

  1. 快速入门
  2. Disruptor类分析
  3. 环形队列的基础操作(不用Disruptor类)
  4. 事件消费知识点小结
  5. 事件消费实战
  6. 常见场景
  7. 等待策略
  8. 知识点补充(终篇)

本篇概览

  • 通过前文的实战,咱们对Disruptor有了初步认识,借助com.lmax.disruptor.dsl.Disruptor类可以轻松完成以下操作:
  1. 环形队列初始化
  2. 指定事件消费者
  3. 启动消费者线程
  • 接下来要面对两个问题:
  1. 深入了解Disruptor类是如何完成上述操作的;
  2. 对Disruptor类有了足够了解时,尝试不用Disruptor,自己动手操作环形队列,实现消息的生产和消费,这样做的目的是加深对Disruptor内部的认识,做到知其所以然;
  • 接下来咱们先解决第一个问题吧,结合Disruptor对象的源码来看看上述三个操作到底做了什么;

环形队列初始化

  • 环形队列初始化发生在实例化Disruptor对象的时候,即Disruptor的构造方法:
public Disruptor(final EventFactory<T> eventFactory, final int ringBufferSize, final ThreadFactory threadFactory)
{
this(RingBuffer.createMultiProducer(eventFactory, ringBufferSize), new BasicExecutor(threadFactory));
}
  • RingBuffer.createMultiProducer方法内部实例化了RingBuffer,如下图红框:

  • 记下第一个重要知识点:创建RingBuffer对象;

指定事件消费者

  • 在前文中,下面这行代码指定了事件由StringEventHandler消费:
disruptor.handleEventsWith(new StringEventHandler(eventCountPrinter));
  • 查看handleEventsWith方法的内部:
public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)
{
return createEventProcessors(new Sequence[0], handlers);
}
  • 展开createEventProcessors方法,如下图,请重点关注创建SequenceBarrier和BatchEventProcessor等操作:

  • 展开上图红框四中的updateGatingSequencesForNextInChain方法,如下图,红框中的ringBuffer.addGatingSequences需要重点关注:

  • 小结一下,disruptor.handleEventsWith方法涉及到四个重要知识点:
  1. 创建SequenceBarrier对象,用于接收ringBuffer中的可消费事件
  2. 创建BatchEventProcessor,负责消费事件
  3. 绑定BatchEventProcessor对象的异常处理类
  4. 调用ringBuffer.addGatingSequences,将消费者的Sequence传给ringBuffer

启动消费者线程

  • 前文已通过日志确定了消费事件的逻辑是在一个独立的线程中执行的,启动消费者线程的代码如下:
disruptor.start();
  • 展开start方法,如下可见,关键代码是consumerInfo.start(executor):
    public RingBuffer<T> start()
{
checkOnlyStartedOnce();
for (final ConsumerInfo consumerInfo : consumerRepository)
{
consumerInfo.start(executor);
} return ringBuffer;
}
  • ConsumerInfo是接口,对应的实现类有EventProcessorInfo和WorkerPoolInfo两种,这里应该是哪种呢?既然来源是consumerRepository,这就要看当初是怎么存入consumerRepository的,前面在分析createEventProcessors方法时,下图红框中的consumerRepository.add被忽略了,现在需要进去看看:

  • 进去后一目了然,可见ConsumerInfo的实现是EventProcessorInfo:

  • 所以,回到前面对consumerInfo.start(executor)方法的分析,这里要看的就是EventProcessorInfo的start方法了,如下图,非常简单,就是启动一个线程执行eventprocessor(这个eventprocessor是BatchEventProcessor对象):

  • 小结一下,disruptor.start方法涉及到一个重要知识点:
  1. 启动独立线程,用来执行消费事件的业务逻辑;

消费事件的逻辑

  • 为了理解消息处理逻辑,还要重点关注BatchEventProcessor.processEvents方法,如下图所示,其实也很简单,就是不停的从环形队列取出可用的事件,然后再更新自己的Sequence,相当于标记已经消费到哪里了:

总结

最后总结Disruptor类的重要功能:

  1. 创建环形队列(RingBuffer对象)
  2. 创建SequenceBarrier对象,用于接收ringBuffer中的可消费事件
  3. 创建BatchEventProcessor,负责消费事件
  4. 绑定BatchEventProcessor对象的异常处理类
  5. 调用ringBuffer.addGatingSequences,将消费者的Sequence传给ringBuffer
  6. 启动独立线程,用来执行消费事件的业务逻辑
  • 聪明的您一定会发现,本文并没有全面分析Disruptor类的源码,例如after、shutdown等方法都没有提到,确实如此,欣宸在此给您道歉了,本篇的重点是找出那些与基本功能有关代码,为后面的实战提供理论指导(不用Disruptor类实现消息生产消费的实战),因此很多高级功能都跳过了;

理解官方流程图

  • 此时再看官方流程图,聪明的您应该很快就能理解此图表达的意思:每个消费者都有自己的Sequence,通过此Sequence取得自己在环形队列中消费的位置,再通过SequenceBarrier来等待可用事件的出现,等到事件出现了就用get方法取出具体的事件,给EventHandler来处理:

后续预告

  • 此时,咱们对Disruptor类已经有了比较深入的理解,接下来的文章,咱们会尝试不用Disruptor类,仅凭着对RingBuffer对象的操作来实现以下三种功能:
  1. 100个事件,单个消费者消费;
  2. 100个事件,三个消费者,每个都独自消费这个100个事件;
  3. 100个事件,三个消费者共同消费这个100个事件;

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...

https://github.com/zq2599/blog_demos

disruptor笔记之二:Disruptor类分析的更多相关文章

  1. Java笔记(二)类

    类 一.类的基础 1.类---一种自定义数据类型. 2.与方法内创建局部变量不同,在创建对象的时候,所有的实例变量都会分配 一个默认值,这与创建数组的时候是类似的. 3.在{}对实例变量内赋值: in ...

  2. Wireshark学习笔记(二)取证分析案例详解

    @ 目录 练习一:分析用户FTP操作 练习二:邮件读取 练习三:有人在摸鱼? 练习一:分析用户FTP操作 已知抓包文件中包含了用户登录FTP服务器并进行交互的一个过程,你能否通过wireshark分析 ...

  3. 《JAVA编程那点事儿》读书笔记(二)——类和对象

    方法: 1. 基本的main方法: public static void main(String[] args) 2.静态方法内部调用非静态方法:重新声明一个类,通过这个类来调用非静态方法 publi ...

  4. objective-C学习笔记(二)类 class 和 结构 struct

    Objective-C的类型 引用类型 类 class 指针 pointer 块 block 值类型 基础数值类型 结构 struct 枚举 enum 类型装饰 协议 protocol 类别 cate ...

  5. python cookbook第三版学习笔记十二:类和对象(三)创建新的类或实例属性

    先介绍几个类中的应用__getattr__,__setattr__,__get__,__set__,__getattribute__,. __getattr__:当在类中找不到attribute的时候 ...

  6. Java学习笔记(二)——类和对象

    [1]类是模子,确定对象将会拥有的特征(属性)和行为(方法). [2]类的特点:类是对象的类型: 具有相同属性和方法的一组对象的集合. [3]属性:对象具有的各种特征(每个对象的每个属性都拥有特定值) ...

  7. jvm的学习笔记:二、类的初始化,代码实战(3)

    首次主动此用导致类的初始化 MyParent4 myParent4 = new MyParent4(); MyParent4 myParent5 = new MyParent4(); 输出: MyPa ...

  8. jvm的学习笔记:二、类的初始化,代码实战(2)

    常量在编译阶段,会存在调用这个常量的方法的所在的类的常量池当中 System.out.println(MyParent2.str); 输出: hello parent2 依据:在MyTest2类调用M ...

  9. jvm的学习笔记:二、类的初始化,代码实战(1)

    对于静态字段来说,直接定义该字段的类才会被初始化 System.out.println(MyChild1.str); 输出: myParent1 static block hello myParent ...

随机推荐

  1. 如何发送一个http请求—apipost

    API界面功能布局 API请求参数 Header 参数 你可以设置或者导入 Header 参数,cookie也在Header进行设置 Query 参数 Query 支持构造URL参数,同时支持 RES ...

  2. 【原创】Java内存攻击技术漫谈

    前言 Java技术栈漏洞目前业已是web安全领域的主流战场,随着IPS.RASP等防御系统的更新迭代,Java攻防交战阵地已经从磁盘升级到了内存里面. 在今年7月份上海银针安全沙龙上,我分享了< ...

  3. 安鸾CTF Writeup wordpress 01

    题目一: wordpress 01 URL:http://whalwl.site:8041/ wordpress 站思路就是先用wpscan 进行扫描检测一遍. wpscan 使用方法可以参考两篇文章 ...

  4. hdmi 随笔

    从图片来看,每张图片开始传输的是45像素的垂直同步, 1.控制数据贯穿所有时间,没个不是控制数据的传输都被控制数据包围.控制数据还要通过控制位指示,下一个数据是数据岛还是视频信号. 2.terc4 全 ...

  5. 题解 a

    传送门 和入阵曲那题很像 这里 \(n\) 很小,可以直接 \(n^2\) 压成一维考虑 然后就是对每个 \(j\) 查询 \([j-r, j-l]\) 中数的个数 这里我是用树状数组求的,带个log ...

  6. 解决log4net多进程日志文件被占用

    <log4net debug="true"> <appender name="RollingLogFileAppender" type=&qu ...

  7. 参数化SQL

    原文:http://www.cnblogs.com/aito/archive/2010/08/25/1808569.html 避免SQL注入的方法有两种:一是所有的SQL语句都存放在存储过程中,这样不 ...

  8. 一个简单的 aiax请求例子

    <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...

  9. LeetCode入门指南 之 二分搜索

    上图表示常用的二分查找模板: 第一种是最基础的,查找区间左右都为闭区间,比较后若不等,剩余区间都不会再包含mid:一般在不需要确定目标值的边界时,用此法即可. 第二种查找区间为左闭右开,要确定targ ...

  10. Android常见面试题(一)

    ANDROID(一) Activity 1.什么是Activity? 请描述一下生命周期 Activity: 一个Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务,例 ...