Disruptor是一个高性能的异步处理框架,或者可以认为是最快的消息框架(轻量的JMS),也可以认为是一个观察者模式的实现,或者事件监听模式的实现。

在使用之前,首先说明disruptor主要功能加以说明,你可以理解为他是一种高效的"生产者-消费者"模型。也就性能远远高于传统的BlockingQueue容器。

在Disruptor中,我们想实现hello world 需要如下几步骤:
第一:建立一个Event类
第二:建立一个工厂Event类,用于创建Event类实例对象
第三:需要有一个监听事件类,用于处理数据(Event类)
第四:我们需要进行测试代码编写。实例化Disruptor实例,配置一系列参数。然后我们对Disruptor实例绑定监听事件类,接受并处理数据。
第五:在Disruptor中,真正存储数据的核心叫做RingBuffer,我们通过Disruptor实例拿到它,然后把数据生产出来,把数据加入到RingBuffer的实例对象中即可。

Disruptor对应就是一个容器,Event类相当于data数据,把Event存储在容器中,然后Disruptor把Event发送给消费者

消费者需要注册一个EventHandle,用来处理接收到的数据

LongEventHandler:就是消费者,Disruptor直接将数据发送给LongEventHandler去处理数据

你想想Disruptor存存储数据,必须利用到RingBuffer

LongEventProducer生产者生产的数据要存储在RingBuffer中

生产者产生数据必须遵循下面的四个步骤:

//1.可以把ringBuffer看做一个事件队列,那么next就是得到下面一个事件槽

//2.用上面的索引取出一个空的事件用于填充(获取该序号对应的事件对象)

//3.获取要通过事件传递的业务数据

//4.发布事件
//注意,最后的 ringBuffer.publish 方法必须包含在 finally 中以确保必须得到调用;如果某个请求的 sequence 未被提交,将会堵塞后续的发布操作或者其它的 producer。

我们来看下面的一个helloword的代码:

目前我们使用disruptor已经更新到了3.x版本,比之前的2.x版本性能更加的优秀,提供更多的API使用方式。
下载disruptor-3.3.2.jar引入我们的项目既可以开始disruptor之旅。
在使用之前,首先说明disruptor主要功能加以说明,你可以理解为他是一种高效的"生产者-消费者"模型。也就性能远远高于传统的BlockingQueue容器

数据类:

package bhz.base;

//http://ifeve.com/disruptor-getting-started/
public class LongEvent {
private long value;
public long getValue() {
return value;
} public void setValue(long value) {
this.value = value;
}
}

产生数据的数据工厂:

package bhz.base;

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

消费者:disruptor收到数据之后,将数据发送给消费者处理,消费者需要实现EventHandle接口

package bhz.base;

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());
} }

消费者直接将收到的数据打印出来

生产者

LongEventProducer生产者生产的数据要存储在RingBuffer中

生产者产生数据必须遵循下面的四个步骤:

//1.可以把ringBuffer看做一个事件队列,那么next就是得到下面一个事件槽

//2.用上面的索引取出一个空的事件用于填充(获取该序号对应的事件对象)

//3.获取要通过事件传递的业务数据

//4.发布事件

package bhz.base;

import java.nio.ByteBuffer;

import com.lmax.disruptor.RingBuffer;
/**
* 很明显的是:当用一个简单队列来发布事件的时候会牵涉更多的细节,这是因为事件对象还需要预先创建。
* 发布事件最少需要两步:获取下一个事件槽并发布事件(发布事件的时候要使用try/finnally保证事件一定会被发布)。
* 如果我们使用RingBuffer.next()获取一个事件槽,那么一定要发布对应的事件。
* 如果不能发布事件,那么就会引起Disruptor状态的混乱。
* 尤其是在多个事件生产者的情况下会导致事件消费者失速,从而不得不重启应用才能会恢复。
* <B>系统名称:</B><BR>
* <B>模块名称:</B><BR>
* <B>中文类名:</B><BR>
* <B>概要说明:</B><BR>
* @author 北京尚学堂(alienware)
* @since 2015年11月23日
*/
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);
}
} }

接下来我们来看下主程序:生产者发送到1-100的数据,消费者收到数据将数据打印出来

package bhz.base;

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 m = 0; m<100; m++){
byteBuffer.putLong(0, m);
producer.onData(byteBuffer);
//Thread.sleep(1000);
} disruptor.shutdown();//关闭 disruptor,方法会堵塞,直至所有的事件都得到处理;
executor.shutdown();//关闭 disruptor 使用的线程池;如果需要的话,必须手动关闭, disruptor 在 shutdown 时不会自动关闭; }
}

我们来】看看程序运行的结果:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

对应生产者官方推荐我们使用下面的代码:

package bhz.base;

import java.nio.ByteBuffer;

import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer; /**
* Disruptor 3.0提供了lambda式的API。这样可以把一些复杂的操作放在Ring Buffer,
* 所以在Disruptor3.0以后的版本最好使用Event Publisher或者Event Translator来发布事件
* <B>系统名称:</B><BR>
* <B>模块名称:</B><BR>
* <B>中文类名:</B><BR>
* <B>概要说明:</B><BR>
* @author 北京尚学堂(alienware)
* @since 2015年11月23日
*/
public class LongEventProducerWithTranslator { //一个translator可以看做一个事件初始化器,publicEvent方法会调用它
//填充Event
private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR =
new EventTranslatorOneArg<LongEvent, ByteBuffer>() {
@Override
public void translateTo(LongEvent event, long sequeue, ByteBuffer buffer) {
event.setValue(buffer.getLong(0));
}
}; private final RingBuffer<LongEvent> ringBuffer; public LongEventProducerWithTranslator(RingBuffer<LongEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
} public void onData(ByteBuffer buffer){
ringBuffer.publishEvent(TRANSLATOR, buffer);
} }

主程序的代码也要做相应的修改

LongEventProducerWithTranslator producer = new LongEventProducerWithTranslator(ringBuffer);
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
for(long m = 0; m<100; m++){
byteBuffer.putLong(0, m);
producer.onData(byteBuffer);
//Thread.sleep(1000);
}

disruptor架构一的更多相关文章

  1. disruptor架构四 多生产者多消费者执行

    1.首先介绍下那个时候使用RingBuffer,那个时候使用disruptor ringBuffer比较适合场景比较简单的业务,disruptor比较适合场景较为复杂的业务,很多复杂的结果必须使用di ...

  2. disruptor架构三 使用场景更加复杂的场景

    先c1和c2并行消费生产者产生的数据,然后c3再消费该数据 我们来使用代码实现:我们可以使用Disruptor实例来实现,也可以不用产生Disruptor实例,直接调用RingBuffer的api来实 ...

  3. disruptor架构三 使用场景 使用WorkHandler和BatchEventProcessor辅助创建消费者

    在helloWorld的实例中,我们创建Disruptor实例,然后调用getRingBuffer方法去获取RingBuffer,其实在很多时候,我们可以直接使用RingBuffer,以及其他的API ...

  4. disruptor架构二

    小故事:Disruptor说的是生产者和消费者的故事. 有一个数组.生产者往里面扔芝麻.消费者从里面捡芝麻. 但是扔芝麻和捡芝麻也要考虑速度的问题. 1 消费者捡的比扔的快 那么消费者要停下来.生产者 ...

  5. Disruptor 源码阅读笔记--转

    原文地址:http://coderbee.net/index.php/open-source/20130812/400 一.Disruptor 是什么? Disruptor 是一个高性能异步处理框架, ...

  6. Disruptor-net 3.3.0

    Disruptor 介绍 Disruptor 是LMX开源出来的java编写的一个并发消息处理器,在队列中一边生产者放入消息,另外一边消费者并行取出处理,其核心是根据现代CPU硬件缓存特点发明不同于通 ...

  7. Disruptor-架构思维的转变

    相对于无锁技术,Disruptor对于架构思维的转变,才是其最大亮点. Pub Event 说到RingBuffer做的队列,通常都说的是“一读一写“,或者“多读一写“.而Disruptor天生是为“ ...

  8. 架构师养成记--15.Disruptor并发框架

    一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...

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

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

随机推荐

  1. 创建HttpFilter与理解多个Filter代码的执行顺序

    1.自定义的HttpFilter,实现Filter接口 HttpFilter package com.aff.filter; import java.io.IOException; import ja ...

  2. 设计一个多功能的MyTime类 代码参考

    #include <iostream> #include <cstdio> using namespace std; class MyTime { private: int h ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)

    上一篇(https://www.cnblogs.com/meowv/p/12971041.html)使用HtmlAgilityPack抓取壁纸数据成功将图片存入数据库,本篇继续来完成一个全网各大平台的 ...

  4. python调用大漠插件教程02大漠插件绑定测试工具

    什么是大漠插件绑定测试工具? 这是大漠插件为了方便使用者调试绑定窗口的模式而设计的,因为有些程序不会接受一般的鼠键事件的响应模式,每个程序所需要的响应模式都不尽相同,所以这个工具可以使我们在绑定窗口时 ...

  5. Parrot os配置源更新

    每次都是忘了怎么配置,去官网查文档,这记一下 一.源文件配置注意 首先要注意Parrot官方软件库的默认更新源文件不在 /etc/apt/sources.list 而是 /etc/apt/source ...

  6. Vue中控制更新的方式

    一.  强制更新的实例方法   vm.$forceUpdate() 迫使 Vue 实例重新渲染.注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件. 在没有留意到数组或对象的变更检测注意事 ...

  7. MySQL 高级—— 锁机制

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.锁的概述 1.锁的定义 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除传统的计 ...

  8. ASP.NET中IHttpHandler与IHttpModule的区别(带样例说明)

    IHttpModule相对来说,是一个网页的添加 IHttpHandler相对来说,却是网页的替换 先建一个HandlerDemo的类 using System; using System.Colle ...

  9. Java实现 LeetCode 507 完美数

    507. 完美数 对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为"完美数". 给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False ...

  10. Java实现 LeetCode 406 根据身高重建队列

    406. 根据身高重建队列 假设有打乱顺序的一群人站成一个队列. 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数. 编写一个算法来重建这个队列. ...