图解Disruptor框架(二):核心概念

概述

上一个章节简单的介绍了了下Disruptor,这节就是要好好的理清楚Disruptor中的核心的概念。并且会给出个HelloWorld的小例子。

在正式开始之前,我觉得有一点我感触非常的深刻,那就是:外国人取的类名真的真的非常的合适以及形象!看看接下来的内容就知道了!

核心概念介绍

下面这张图,非常好的总结了Disruptor中需要了解的核心概念:


多生产者多消费者模型
  • RingBuffer: Disruptor中的数据结构,用于存储生产者生产的数据(在Disruptor中,叫做Event)。

  • Sequence:序号。在Disruptor框架中,任何地方都有序号。生产者生产的数据放在RingBuffer中的哪个位置,消费者应该消费哪个位置的数据,RingBuffer中的某个位置的数据是什么,这些都是由这个序号来决定的。这个序号可以简单的理解为一个AtomicLong类型的变量。其使用了padding的方法去消除缓存的伪共享问题。

  • Sequencer:序号生成器。这个类主要是用来协调生产者的。在生产者生产数据的时候,Sequencer会产生一个可用的序号(Sequence),然后生产者就乖乖的把数据放在那里了。(此处不严谨,后续会说明原因。)

  • SequencerBarrier:序号屏障。(我觉得这个名字真的太形象了!)我们都知道,消费者在消费数据的时候,需要知道消费哪个位置的数据。消费者总不能自己想取哪个数据消费,就取哪个数据消费吧。(这样多混乱啊!)这个SequencerBarrier起到的就是这样一个“栅栏”般的阻隔作用。你消费者想消费数据,得,我告诉你一个序号(Sequence),你去消费那个位置上的数据。要是没有数据,就好好等着吧(怎么等也是有讲究的)。

先小结一下:Sequence、Sequencer、SequencerBarrier这三个概念一开始我是比较难以理解的。但是总结一下,无非就是Ringbuffer中哪里都需要用到序号,而Sequencer用于生产者生产的时候产生序号,SeqencerBarrier就是协调生产者与消费者,并且告诉消费者一个可以用于消费的序号!

  • Wait Strategy:等待策略。设想一种这样的情景:生产者生产的非常慢,而消费者消费的非常快。那么必然会出现数据不够的情况,这个时候消费者怎么进行等待呢?WaitStrategy就是为了解决问题而诞生的。

  • Event:数据、事件。这个Event就是我们希望RingBuffer存储的数据类型。这个是我们用户自己定义的。我们可以定义为任何事情,比如处理订单、消息等等。

  • EventHandler:事件处理器。当RingBuffer中有数据的时候,消费者怎么去对数据进行处理,就是由这个类去决定的。

  • Producer:生产者。用于生产数据。

上述就是Disruptor框架中的核心概念。如果不是非常的理解,可以先跟着我下面的例子去手敲一遍入门的程序,去体验一下。然后看看源码加深理解。

第一个入门小程序

首先是订单类Order


  1. @Data 

  2. public class Order { 


  3. /** 

  4. * 订单ID 

  5. */ 

  6. private String id; 


  7. /** 

  8. * 订单名字 

  9. */ 

  10. private String name; 


  11. /** 

  12. * 用于记录这个对象创建的时间 

  13. */ 

  14. private Date createTime; 




订单工厂类OrderFactory

  1. public class OrderFactory implements EventFactory<Order> { 

  2. public Order newInstance() { 

  3. Order order = new Order(); 

  4. order.setCreateTime(new Date()); 

  5. return order; 





这个类主要用于ringbuffer构造的时候对其中存放的数据进行预加载。

相应的源码如下面所示:


  1. /** 

  2. * 用于构造的时候需加载数据 

  3. * @param eventFactory 

  4. */ 

  5. private void fill(EventFactory<E> eventFactory) 



  6. for (int i = 0; i < bufferSize; i++) 



  7. // entries数组就是ringbuffer中用于存放数据的数组 

  8. entries[BUFFER_PAD + i] = eventFactory.newInstance(); 





生产者Producer


  1. public class Producer { 


  2. private RingBuffer<Order> ringBuffer; 



  3. public Producer(RingBuffer<Order> ringBuffer) { 

  4. this.ringBuffer = ringBuffer; 




  5. public void sendData(String s) { 

  6. long sequence = ringBuffer.next(); 

  7. Order order = ringBuffer.get(sequence); 

  8. order.setId(s); 

  9. ringBuffer.publish(sequence); 





消费者Comsumer


  1. @Data 

  2. public class Comsumer implements WorkHandler<Order> { 


  3. /** 

  4. * 消费者ID 

  5. */ 

  6. private String comsumerId; 


  7. /** 

  8. * 记录消费的次数 

  9. */ 

  10. public static final AtomicInteger count = new AtomicInteger(0); 



  11. public Comsumer(String comsumerId) { 

  12. this.comsumerId = comsumerId; 




  13. @Override 

  14. public void onEvent(Order event) throws Exception { 

  15. System.out.println("消费者:"+comsumerId+"消费了数据,ID="+event.getId()+"Name="+event.getName()); 

  16. count.incrementAndGet(); 





主函数Main


  1. public class Main { 

  2. public static void main(String[] args) throws InterruptedException { 


  3. // 构造ringbuffer 

  4. RingBuffer<Order> ringBuffer = RingBuffer.create( 

  5. ProducerType.MULTI, 

  6. new OrderFactory(), 

  7. 1024*1024, 

  8. new BlockingWaitStrategy() 

  9. ); 


  10. // 创建一个序号屏障 

  11. SequenceBarrier barrier = ringBuffer.newBarrier(); 


  12. // 创建消费者数组 

  13. Comsumer[] comsumers = new Comsumer[10]; 

  14. for (int i = 0; i < comsumers.length; i++) { 

  15. comsumers[i] = new Comsumer("comsumer"+i); 




  16. // 创建多消费者的工作池 

  17. WorkerPool<Order> workerPool = new WorkerPool<Order>( 

  18. ringBuffer, 

  19. barrier, 

  20. new EventExceptionHandler(), 

  21. comsumers 

  22. ); 


  23. // 设置多个消费者的sequence序号 用于单独统计消费进度, 并且设置到ringbuffer中 

  24. ringBuffer.addGatingSequences(workerPool.getWorkerSequences()); 


  25. workerPool.start(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); 


  26. // -----消费者创建完毕----- 



  27. // -----创建生产者------ 

  28. // 用于阻塞生产者生产数据 

  29. CountDownLatch latch = new CountDownLatch(1); 


  30. for(int i = 0; i < 100; i++) { 

  31. final Producer producer = new Producer(ringBuffer); 

  32. new Thread(new Runnable() { 

  33. public void run() { 

  34. try { 

  35. // 阻塞生产者 

  36. latch.await(); 

  37. } catch (Exception e) { 

  38. e.printStackTrace(); 



  39. for(int j = 0; j<100; j++) { 

  40. producer.sendData(UUID.randomUUID().toString()); 





  41. }).start(); 




  42. System.err.println("----------线程创建完毕,开始生产数据----------"); 

  43. // 放行生产者,让其生产数据 

  44. latch.countDown(); 


  45. // 等待消费者消费完数据 

  46. Thread.sleep(2000); 


  47. System.err.println("消费次数:"+Comsumer.count); 





  48. static class EventExceptionHandler implements ExceptionHandler<Order> { 

  49. public void handleEventException(Throwable ex, long sequence, Order event) { 




  50. public void handleOnStartException(Throwable ex) { 




  51. public void handleOnShutdownException(Throwable ex) { 







运行结果:

上述的代码主要就是生产者生产了10000个数据,然后消费者再消费这些数据。可以看到结果是正确的。

上述这个小小的demo就结束了。接下来会再看看Disruptor的操作,例如链式操作、菱形操作、多边形操作等等。

总结

这一个小节,阐述了Disruptor中的一些核心概念,并编写了一个helloworld程序。如果读者觉得还是比较难理解,那就多敲几遍。这个没有办法的。

项目源码地址: https://gitee.com/cjh95/disruptor_blog/tree/master

参考资料

  1. 官网的简单介绍 https://github.com/LMAX-Exchange/disruptor/wiki/Introduction
  2. 伪共享 https://www.cnblogs.com/cyfonly/p/5800758.html

图解Disruptor框架(二):核心概念的更多相关文章

  1. 图解Disruptor框架(一):初识Ringbuffer

    图解Disruptor框架(一):初识Ringbuffer 概述 1. 什么是Disruptor?为什么是Disruptor? Disruptor是一个性能十分强悍的无锁高并发框架.在JUC并发包中, ...

  2. fusionjs 学习二 核心概念

    核心概念 middleware 类似express 的中间件模型(实际上是构建在koa中间件模型上的),但是和koa 的中间件有差异 fusionjs 的中间件同时可以运行在浏览器页面加载的时候 se ...

  3. Spring框架的核心概念是什么?需要掌握的知识点都有哪些?

    Spring其主要精髓 就是IOC和AOP.掌握好了这两点对于理解Spring的思想颇有意义. IOC(英文 Inversion of Control)就是控制反转的意思.就是把新建对象(new Ob ...

  4. 【ShardingSphere】ShardingSphere学习(二)-核心概念-SQL

    逻辑表 水平拆分的数据库(表)的相同逻辑和数据结构表的总称. 例:订单数据根据主键尾数拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名为t_order. 真实表 在分片的数 ...

  5. Disruptor并发框架 (二)核心概念场景分析

    核心术语 RingBuffer(容器): 被看作Disruptor最主要的组件,然而从3.0开始RingBuffer仅仅负责存储和更新在Disruptor中流通的数据.对一些特殊的使用场景能够被用户( ...

  6. disruptor 核心概念 二

    一.Disruptor图解 二.disruptor核心概念 1.RingBuffer到底是啥?正如名字所说的一样,他是一个环(首尾相接的环)它用做在不同上下文(线程)间传递数据的buffer Ring ...

  7. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  8. Storm 学习之路(二)—— Storm核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的Storm流处理程序被称为Storm topology(拓扑).它是一个是由Spouts 和Bolts通过Stream连接起来的 ...

  9. Storm 系列(二)—— Storm 核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的 Storm 流处理程序被称为 Storm topology(拓扑).它是一个是由 Spouts 和 Bolts 通过 Stre ...

随机推荐

  1. Django之ORM跨表操作

    Django之ORM表查询及添加记录 一.创建表 - 书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-man ...

  2. Luogu P1462 通往奥格瑞玛的道路 二分答案+最短路

    先二分答案,再跑最短路,跑的时候遇到 过路费超过二分的答案的 就不拿他更新最短路 #include<cstdio> #include<iostream> #include< ...

  3. 题解 P1006 传纸条

    传送门 其实我觉得这个跟P1004挺类似(又是动规) 题解P1004 #include<iostream> #include<cstdio> #include<cstri ...

  4. GUI的最终选择 Tkinter(六):Canvas组件

    Canvas组件,是一个可以让你任性的组件,一个可以让你随心所欲地绘制界面的组件.Canvas是一个通用的组件,它通常用于显示和编辑图形,可以用它来绘制直线,圆形,多边形,甚至是绘制其他组件. 在Ca ...

  5. net core (上)

    net core (上) 本文是基于Windows10的. 下载地址: https://code.visualstudio.com/ insider 版下载地址: https://code.visua ...

  6. PartTime_一些网站

    1. http://www.sxsoft.com/ 貌似 搜搜"破解",无符合条件的结果 http://www.taskcity.com/ "智城",貌似 符合 ...

  7. [RDL]多级占比做法

    先添加[店铺],然后,对[店铺]添加父组,记得勾选[添加组头] 然后直接删除[区域2],[省份2] 添加到[店铺列] [区域]行,生意额占比表达式:=sum(Fields!生意额.Value)/Sum ...

  8. CM5.7.2 yum离线安装笔记

    一.建立yum本地服务源(yum支持http和ftp两种协议,这里使用http协议)  1.启动httpd服务   启动命令:service httpd start   关闭命令:service ht ...

  9. 超全面的vue.js使用总结

    一.Vue.js组件 vue.js构建组件使用 Vue.component('componentName',{ /*component*/ }): 这里注意一点,组件要先注册再使用,也就是说: Vue ...

  10. 快速开启MySQL慢日志查询的方法

    MySQL慢日志查询对于很多刚接触MySQL数据的新人来说比较陌生,下面就为您介绍MySQL慢日志查询的用法和好处,供您参考.  mysql有一个功能就是可以log下来运行的比较慢的sql语句,默认是 ...