架构师养成记--15.Disruptor并发框架
一、概述
disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人。
这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端
缓存中的数据是主动发给消费端的,而不是像一般的生产者消费者模式那样,消费端去缓存中取数据。
可以将disruptor理解为,基于事件驱动的高效队列、轻量级的JMS
disruptor学习网站:http://ifeve.com/disruptor-getting-started
二、开发流程
1.建Event类(数据对象)
2.建立一个生产数据的工厂类,EventFactory,用于生产数据;
3.监听事件类(处理Event数据)
4.实例化Disruptor,配置参数,绑定事件;
5.建存放数据的核心 RingBuffer,生产的数据放入 RungBuffer。
三、HelloWord
1.入口
- import java.nio.ByteBuffer;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import com.lmax.disruptor.RingBuffer;
- import com.lmax.disruptor.YieldingWaitStrategy;
- import com.lmax.disruptor.dsl.Disruptor;
- import com.lmax.disruptor.dsl.ProducerType;
- public class LongEventMain {
- public static void main(String[] args) throws Exception {
- //创建缓冲池
- ExecutorService executor = Executors.newCachedThreadPool();
- //创建工厂
- LongEventFactory factory = new LongEventFactory();
- //创建bufferSize ,也就是RingBuffer大小,必须是2的N次方
- int ringBufferSize = 1024 * 1024; //
- /**
- //BlockingWaitStrategy 是最低效的策略,但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现
- WaitStrategy BLOCKING_WAIT = new BlockingWaitStrategy();
- //SleepingWaitStrategy 的性能表现跟BlockingWaitStrategy差不多,对CPU的消耗也类似,但其对生产者线程的影响最小,适合用于异步日志类似的场景
- WaitStrategy SLEEPING_WAIT = new SleepingWaitStrategy();
- //YieldingWaitStrategy 的性能是最好的,适合用于低延迟的系统。在要求极高性能且事件处理线数小于CPU逻辑核心数的场景中,推荐使用此策略;例如,CPU开启超线程的特性
- WaitStrategy YIELDING_WAIT = new YieldingWaitStrategy();
- */
- //创建disruptor
- Disruptor<LongEvent> disruptor =
- new Disruptor<LongEvent>(factory, ringBufferSize, executor, ProducerType.SINGLE, new YieldingWaitStrategy());
- // 连接消费事件方法
- disruptor.handleEventsWith(new LongEventHandler());
- // 启动
- disruptor.start();
- //Disruptor 的事件发布过程是一个两阶段提交的过程:
- //发布事件
- RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
- LongEventProducer producer = new LongEventProducer(ringBuffer);
- //LongEventProducerWithTranslator producer = new LongEventProducerWithTranslator(ringBuffer);
- ByteBuffer byteBuffer = ByteBuffer.allocate(8);
- for(long l = 0; l<100; l++){
- byteBuffer.putLong(0, l);
- producer.onData(byteBuffer);
- //Thread.sleep(1000);
- }
- disruptor.shutdown();//关闭 disruptor,方法会堵塞,直至所有的事件都得到处理;
- executor.shutdown();//关闭 disruptor 使用的线程池;如果需要的话,必须手动关闭, disruptor 在 shutdown 时不会自动关闭;
- }
- }
2.数据对象:
- public class LongEvent {
- private long value;
- public long getValue() {
- return value;
- }
- public void setValue(long value) {
- this.value = value;
- }
- }
3.Event工厂
- import com.lmax.disruptor.EventFactory;
- // 需要让disruptor为我们创建事件,我们同时还声明了一个EventFactory来实例化Event对象。
- public class LongEventFactory implements EventFactory {
- @Override
- public Object newInstance() {
- return new LongEvent();
- }
- }
4.生产者
- import java.nio.ByteBuffer;
- import com.lmax.disruptor.RingBuffer;
- /**
- * 很明显的是:当用一个简单队列来发布事件的时候会牵涉更多的细节,这是因为事件对象还需要预先创建。
- * 发布事件最少需要两步:获取下一个事件槽并发布事件(发布事件的时候要使用try/finnally保证事件一定会被发布)。
- * 如果我们使用RingBuffer.next()获取一个事件槽,那么一定要发布对应的事件。
- * 如果不能发布事件,那么就会引起Disruptor状态的混乱。
- * 尤其是在多个事件生产者的情况下会导致事件消费者失速,从而不得不重启应用才能会恢复。
- */
- public class LongEventProducer {
- private final RingBuffer<LongEvent> ringBuffer;
- public LongEventProducer(RingBuffer<LongEvent> ringBuffer){
- this.ringBuffer = ringBuffer;
- }
- /**
- * onData用来发布事件,每调用一次就发布一次事件
- * 它的参数会用过事件传递给消费者
- */
- public void onData(ByteBuffer bb){
- //1.可以把ringBuffer看做一个事件队列,那么next就是得到下面一个事件槽
- long sequence = ringBuffer.next();
- try {
- //2.用上面的索引取出一个空的事件用于填充(获取该序号对应的事件对象)
- LongEvent event = ringBuffer.get(sequence);
- //3.获取要通过事件传递的业务数据
- event.setValue(bb.getLong(0));
- } finally {
- //4.发布事件
- //注意,最后的 ringBuffer.publish 方法必须包含在 finally 中以确保必须得到调用;如果某个请求的 sequence 未被提交,将会堵塞后续的发布操作或者其它的 producer。
- ringBuffer.publish(sequence);
- }
- }
- }
5.消费者
- import com.lmax.disruptor.EventHandler;
- //我们还需要一个事件消费者,也就是一个事件处理器。这个事件处理器简单地把事件中存储的数据打印到终端:
- public class LongEventHandler implements EventHandler<LongEvent> {
- @Override
- public void onEvent(LongEvent longEvent, long l, boolean b) throws Exception {
- System.out.println(longEvent.getValue());
- }
- }
架构师养成记--15.Disruptor并发框架的更多相关文章
- 架构师养成记--16.disruptor并发框架中RingBuffer的使用
很多时候我们只需要消息中间件这样的功能,那么直需要RinBuffer就可以了. 入口: import java.util.concurrent.Callable; import java.util.c ...
- 架构师养成记--10.master-worker模式
master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...
- 架构师养成记--8.Queue
一.ConcurrentLinkedQueue 是一个适合在高并发场景下,无锁,无界的,先进先出原则.不允许为null值,add().offer()加入元素,这两个方法没区别:pull().peek( ...
- 架构师养成记--35.redis集群搭建
前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...
- 架构师养成记--32.Redis高级(安全 主从复制)
Redis高级命令及特性 keys * 返回满足的所有键值(*表示模糊匹配) exists 是否存在指定的key(返回1表示存在,0表示不存在) expire 设置某个key的过期时间,使用ttl查看 ...
- 架构师养成记--29.redis开篇
主要有从下几点讲解 NOSQL(Redis) 简介.redis安装与部署 Redis基础事件类型详解 Redis高级命令 Redis与java的使用 Redis集群搭建 Redis集群与spring的 ...
- 架构师养成记--21.netty编码解码
背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...
- 架构师养成记--19.netty
一.Netty初步 为什么选择Netty? 和NIO比较,要实现一个通信要简单得很多,性能很好.分布式消息中间件.storm.Dubble都是使用Netty作为底层通信. Netty5.0要求jdk1 ...
- 架构师养成记--17.disrunptor 多生产者多消费者
入口: import java.nio.ByteBuffer; import java.util.UUID; import java.util.concurrent.CountDownLatch; i ...
随机推荐
- elasticsearch高级配置一 ---- 分片分布规则设置
cluster.routing.allocation.allow_rebalance 设置根据集群中机器的状态来重新分配分片,可以设置为always, indices_primaries_active ...
- K60——寄存器
(1)PTx_BASE_PTR为GPIO寄存器结构体基址指针(PTR即point to register,x=A/B/C/D/E) /* GPIO - Peripheral instance base ...
- react-native Simulator com+r不能刷新模拟器
这个问题是我按了com + shift + K 调出Simulatior 的时候出现的, 然后虚拟机就刷新不了了, 怎么按com+r都不好使. 在Simulatior的菜单栏选择Hardware -- ...
- Angular版本1.2.4在IE11的IE8模式下出错解决方案
今天,群里一个兄弟抛出一个问题(如上),截图说明. 打断点调试下,貌似是console里面的log方法出错了,如下: 这个是console的log方法,为什么错呢,继续: 我们会发现,在这里是检测fu ...
- fastjson 混淆注意事项
使用fastjson 注意事项,主要表现: 1.加了符号Annotation 的实体类,一使用就会奔溃 2.当有泛型属性时,一使用就奔溃 在调试的时候不会报错,当你要打包签名混淆包的时候,就会出现上述 ...
- Java使用POS打印机(无驱)
使用原因:应项目要求,需要使用打印机,但是如果使用Windows驱动来实现打印,在某些条件下会发生网络堵塞等,而且没有提示,所以为了确保信息的完整,避免数据丢失.我们使用无驱打印(直接写端口的方法), ...
- json的理解及读取
一: JSON 语法是 JavaScript 对象表示语法的子集,其语法规则如下: 数据在键值对中 数据由逗号分隔 花括号保存对象:{} 方括号保存数组:[] 如:[{"name" ...
- 几大排序算法的Java实现
很多的面试题都问到了排序算法,中间的算法和思想比较重要,这边我选择了5种常用排序算法并用Java进行了实现.自己写一个模板已防以后面试用到.大家可以看过算法之后,自己去实现一下. 1.冒泡排序:大数向 ...
- MySql索引总结
索引概念 B+树索引分为聚集索引和非聚集索引(辅助索引),但是两者的数据结构都和B+树一样,区别是存放的内容. 可以说数据库必须有索引,没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能 ...
- javascript判断是否为闰年
//判断年份year是否为闰年,是闰年则返回true,否则返回false function isLeapYear(year){ var a = year % 4; var b = year % 100 ...