一、概述

disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人。

这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端

缓存中的数据是主动发给消费端的,而不是像一般的生产者消费者模式那样,消费端去缓存中取数据。

可以将disruptor理解为,基于事件驱动的高效队列、轻量级的JMS

disruptor学习网站:http://ifeve.com/disruptor-getting-started

二、开发流程

1.建Event类(数据对象)

2.建立一个生产数据的工厂类,EventFactory,用于生产数据;

3.监听事件类(处理Event数据)

4.实例化Disruptor,配置参数,绑定事件;

5.建存放数据的核心 RingBuffer,生产的数据放入 RungBuffer。

三、HelloWord 

1.入口

  1. import java.nio.ByteBuffer;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4.  
  5. import com.lmax.disruptor.RingBuffer;
  6. import com.lmax.disruptor.YieldingWaitStrategy;
  7. import com.lmax.disruptor.dsl.Disruptor;
  8. import com.lmax.disruptor.dsl.ProducerType;
  9.  
  10. public class LongEventMain {
  11.  
  12. public static void main(String[] args) throws Exception {
  13. //创建缓冲池
  14. ExecutorService executor = Executors.newCachedThreadPool();
  15. //创建工厂
  16. LongEventFactory factory = new LongEventFactory();
  17. //创建bufferSize ,也就是RingBuffer大小,必须是2的N次方
  18. int ringBufferSize = 1024 * 1024; //
  19.  
  20. /**
  21. //BlockingWaitStrategy 是最低效的策略,但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现
  22. WaitStrategy BLOCKING_WAIT = new BlockingWaitStrategy();
  23. //SleepingWaitStrategy 的性能表现跟BlockingWaitStrategy差不多,对CPU的消耗也类似,但其对生产者线程的影响最小,适合用于异步日志类似的场景
  24. WaitStrategy SLEEPING_WAIT = new SleepingWaitStrategy();
  25. //YieldingWaitStrategy 的性能是最好的,适合用于低延迟的系统。在要求极高性能且事件处理线数小于CPU逻辑核心数的场景中,推荐使用此策略;例如,CPU开启超线程的特性
  26. WaitStrategy YIELDING_WAIT = new YieldingWaitStrategy();
  27. */
  28.  
  29. //创建disruptor
  30. Disruptor<LongEvent> disruptor =
  31. new Disruptor<LongEvent>(factory, ringBufferSize, executor, ProducerType.SINGLE, new YieldingWaitStrategy());
  32. // 连接消费事件方法
  33. disruptor.handleEventsWith(new LongEventHandler());
  34.  
  35. // 启动
  36. disruptor.start();
  37.  
  38. //Disruptor 的事件发布过程是一个两阶段提交的过程:
  39. //发布事件
  40. RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
  41.  
  42. LongEventProducer producer = new LongEventProducer(ringBuffer);
  43. //LongEventProducerWithTranslator producer = new LongEventProducerWithTranslator(ringBuffer);
  44. ByteBuffer byteBuffer = ByteBuffer.allocate(8);
  45. for(long l = 0; l<100; l++){
  46. byteBuffer.putLong(0, l);
  47. producer.onData(byteBuffer);
  48. //Thread.sleep(1000);
  49. }
  50.  
  51. disruptor.shutdown();//关闭 disruptor,方法会堵塞,直至所有的事件都得到处理;
  52. executor.shutdown();//关闭 disruptor 使用的线程池;如果需要的话,必须手动关闭, disruptor 在 shutdown 时不会自动关闭;
  53.  
  54. }
  55. }

2.数据对象:

  1. public class LongEvent {
  2. private long value;
  3. public long getValue() {
  4. return value;
  5. }
  6.  
  7. public void setValue(long value) {
  8. this.value = value;
  9. }
  10. }

3.Event工厂

  1. import com.lmax.disruptor.EventFactory;
  2. // 需要让disruptor为我们创建事件,我们同时还声明了一个EventFactory来实例化Event对象。
  3. public class LongEventFactory implements EventFactory {
  4.  
  5. @Override
  6. public Object newInstance() {
  7. return new LongEvent();
  8. }
  9. }

4.生产者

  1. import java.nio.ByteBuffer;
  2.  
  3. import com.lmax.disruptor.RingBuffer;
  4. /**
  5. * 很明显的是:当用一个简单队列来发布事件的时候会牵涉更多的细节,这是因为事件对象还需要预先创建。
  6. * 发布事件最少需要两步:获取下一个事件槽并发布事件(发布事件的时候要使用try/finnally保证事件一定会被发布)。
  7. * 如果我们使用RingBuffer.next()获取一个事件槽,那么一定要发布对应的事件。
  8. * 如果不能发布事件,那么就会引起Disruptor状态的混乱。
  9. * 尤其是在多个事件生产者的情况下会导致事件消费者失速,从而不得不重启应用才能会恢复。
  10. */
  11. public class LongEventProducer {
  12.  
  13. private final RingBuffer<LongEvent> ringBuffer;
  14.  
  15. public LongEventProducer(RingBuffer<LongEvent> ringBuffer){
  16. this.ringBuffer = ringBuffer;
  17. }
  18.  
  19. /**
  20. * onData用来发布事件,每调用一次就发布一次事件
  21. * 它的参数会用过事件传递给消费者
  22. */
  23. public void onData(ByteBuffer bb){
  24. //1.可以把ringBuffer看做一个事件队列,那么next就是得到下面一个事件槽
  25. long sequence = ringBuffer.next();
  26. try {
  27. //2.用上面的索引取出一个空的事件用于填充(获取该序号对应的事件对象)
  28. LongEvent event = ringBuffer.get(sequence);
  29. //3.获取要通过事件传递的业务数据
  30. event.setValue(bb.getLong(0));
  31. } finally {
  32. //4.发布事件
  33. //注意,最后的 ringBuffer.publish 方法必须包含在 finally 中以确保必须得到调用;如果某个请求的 sequence 未被提交,将会堵塞后续的发布操作或者其它的 producer。
  34. ringBuffer.publish(sequence);
  35. }
  36. }
  37.  
  38. }

5.消费者

  1. import com.lmax.disruptor.EventHandler;
  2.  
  3. //我们还需要一个事件消费者,也就是一个事件处理器。这个事件处理器简单地把事件中存储的数据打印到终端:
  4. public class LongEventHandler implements EventHandler<LongEvent> {
  5.  
  6. @Override
  7. public void onEvent(LongEvent longEvent, long l, boolean b) throws Exception {
  8. System.out.println(longEvent.getValue());
  9. }
  10.  
  11. }

架构师养成记--15.Disruptor并发框架的更多相关文章

  1. 架构师养成记--16.disruptor并发框架中RingBuffer的使用

    很多时候我们只需要消息中间件这样的功能,那么直需要RinBuffer就可以了. 入口: import java.util.concurrent.Callable; import java.util.c ...

  2. 架构师养成记--10.master-worker模式

    master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...

  3. 架构师养成记--8.Queue

    一.ConcurrentLinkedQueue 是一个适合在高并发场景下,无锁,无界的,先进先出原则.不允许为null值,add().offer()加入元素,这两个方法没区别:pull().peek( ...

  4. 架构师养成记--35.redis集群搭建

    前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...

  5. 架构师养成记--32.Redis高级(安全 主从复制)

    Redis高级命令及特性 keys * 返回满足的所有键值(*表示模糊匹配) exists 是否存在指定的key(返回1表示存在,0表示不存在) expire 设置某个key的过期时间,使用ttl查看 ...

  6. 架构师养成记--29.redis开篇

    主要有从下几点讲解 NOSQL(Redis) 简介.redis安装与部署 Redis基础事件类型详解 Redis高级命令 Redis与java的使用 Redis集群搭建 Redis集群与spring的 ...

  7. 架构师养成记--21.netty编码解码

    背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...

  8. 架构师养成记--19.netty

    一.Netty初步 为什么选择Netty? 和NIO比较,要实现一个通信要简单得很多,性能很好.分布式消息中间件.storm.Dubble都是使用Netty作为底层通信. Netty5.0要求jdk1 ...

  9. 架构师养成记--17.disrunptor 多生产者多消费者

    入口: import java.nio.ByteBuffer; import java.util.UUID; import java.util.concurrent.CountDownLatch; i ...

随机推荐

  1. elasticsearch高级配置一 ---- 分片分布规则设置

    cluster.routing.allocation.allow_rebalance 设置根据集群中机器的状态来重新分配分片,可以设置为always, indices_primaries_active ...

  2. K60——寄存器

    (1)PTx_BASE_PTR为GPIO寄存器结构体基址指针(PTR即point to register,x=A/B/C/D/E) /* GPIO - Peripheral instance base ...

  3. react-native Simulator com+r不能刷新模拟器

    这个问题是我按了com + shift + K 调出Simulatior 的时候出现的, 然后虚拟机就刷新不了了, 怎么按com+r都不好使. 在Simulatior的菜单栏选择Hardware -- ...

  4. Angular版本1.2.4在IE11的IE8模式下出错解决方案

    今天,群里一个兄弟抛出一个问题(如上),截图说明. 打断点调试下,貌似是console里面的log方法出错了,如下: 这个是console的log方法,为什么错呢,继续: 我们会发现,在这里是检测fu ...

  5. fastjson 混淆注意事项

    使用fastjson 注意事项,主要表现: 1.加了符号Annotation 的实体类,一使用就会奔溃 2.当有泛型属性时,一使用就奔溃 在调试的时候不会报错,当你要打包签名混淆包的时候,就会出现上述 ...

  6. Java使用POS打印机(无驱)

    使用原因:应项目要求,需要使用打印机,但是如果使用Windows驱动来实现打印,在某些条件下会发生网络堵塞等,而且没有提示,所以为了确保信息的完整,避免数据丢失.我们使用无驱打印(直接写端口的方法), ...

  7. json的理解及读取

    一: JSON 语法是 JavaScript 对象表示语法的子集,其语法规则如下: 数据在键值对中 数据由逗号分隔 花括号保存对象:{} 方括号保存数组:[] 如:[{"name" ...

  8. 几大排序算法的Java实现

    很多的面试题都问到了排序算法,中间的算法和思想比较重要,这边我选择了5种常用排序算法并用Java进行了实现.自己写一个模板已防以后面试用到.大家可以看过算法之后,自己去实现一下. 1.冒泡排序:大数向 ...

  9. MySql索引总结

    索引概念 B+树索引分为聚集索引和非聚集索引(辅助索引),但是两者的数据结构都和B+树一样,区别是存放的内容. 可以说数据库必须有索引,没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能 ...

  10. javascript判断是否为闰年

    //判断年份year是否为闰年,是闰年则返回true,否则返回false function isLeapYear(year){ var a = year % 4; var b = year % 100 ...