EventProcessor与WorkPool用法--可处理多消费者
单一的生产者,消费者有多个,使用WorkerPool来管理多个消费者;
RingBuffer在生产Sequencer中记录一个cursor,追踪生产者生产到的最新位置,通过WorkSequence和sequence记录整个workpool消费的位置和每个WorkProcessor消费到位置,来协调生产和消费程序
1、定义事件
package com.ljq.disruptor; import java.io.Serializable; /**
* 交易事件数据
*
* @author Administrator
*
*/
@SuppressWarnings("serial")
public class TradeEvent implements Serializable {
private String id; // 订单ID
private String name;
private double price; // 金额 public TradeEvent() {
} public TradeEvent(String id) {
super();
this.id = id;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
} @Override
public String toString() {
return "Trade [id=" + id + ", name=" + name + ", price=" + price + "]";
} }
2、TradeEvent事件消费者
package com.ljq.disruptor; import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.WorkHandler; public class TradeEventHandler implements EventHandler<TradeEvent>, WorkHandler<TradeEvent> {
@Override
public void onEvent(TradeEvent event, long sequence, boolean endOfBatch) throws Exception {
this.onEvent(event);
} /**
* WorkProcessor多线程排队领event然后再执行,不同线程执行不同的event。但是多了个排队领event的过程,这个是为了减少对生产者队列查询的压力
*/
@Override
public void onEvent(TradeEvent event) throws Exception {
// 具体的消费逻辑
System.out.println("consumer:" + Thread.currentThread().getName() + " Event: value=" + event);
}
}
3、EventProcessor消费者-生产者启动类
package com.ljq.disruptor; import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import com.lmax.disruptor.BatchEventProcessor;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.YieldingWaitStrategy; public class EventProcessorMain {
public static void main(String[] args) throws Exception {
long beginTime = System.currentTimeMillis(); // 指定 ring buffer字节大小,必需为2的N次方(能将求模运算转为位运算提高效率 ),否则影响性能
int bufferSize = 1024;
//固定线程数
int nThreads = 4; EventFactory<TradeEvent> eventFactory = new EventFactory<TradeEvent>() {
@Override
public TradeEvent newInstance() {
return new TradeEvent(UUID.randomUUID().toString());
}
}; //RingBuffer. createSingleProducer创建一个单生产者的RingBuffer
//第一个参数叫EventFactory,从名字上理解就是“事件工厂”,其实它的职责就是产生数据填充RingBuffer的区块。
//第二个参数是RingBuffer的大小,它必须是2的整数倍,目的是为了将求模运算转为&运算提高效率
//第三个参数是RingBuffer的生产在没有可用区块的时候(可能是消费者太慢了)的等待策略
final RingBuffer<TradeEvent> ringBuffer = RingBuffer.createSingleProducer(eventFactory, bufferSize, new YieldingWaitStrategy()); //SequenceBarrier, 协调消费者与生产者, 消费者链的先后顺序. 阻塞后面的消费者(没有Event可消费时)
SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); //创建消费者事件处理器, 多线程并发执行,不同线程执行不同的event
BatchEventProcessor<TradeEvent> transProcessor = new BatchEventProcessor<TradeEvent>(ringBuffer, sequenceBarrier, new TradeEventHandler());
//把消费者的消费进度情况注册给RingBuffer结构(生产者),如果只有一个消费者的情况可以省略
ringBuffer.addGatingSequences(transProcessor.getSequence()); //创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
ExecutorService executors = Executors.newFixedThreadPool(nThreads);
//把消费者提交到线程池,说明EventProcessor实现了callable接口
executors.submit(transProcessor); // 生产者,这里新建线程不是必要的
Future<?> future= executors.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
long seq;
for (int i = 0; i < 100000; i++) {
seq = ringBuffer.next();
ringBuffer.get(seq).setPrice(i);
ringBuffer.publish(seq);
}
return null;
}
});
future.get();//等待生产者结束 Thread.sleep(1000); //等上1秒,等消费都处理完成
transProcessor.halt(); //通知事件(或者说消息)处理器 可以结束了(并不是马上结束!!!)
executors.shutdown(); System.out.println(String.format("总共耗时%s毫秒", (System.currentTimeMillis() - beginTime))); }
}
4、WorkerPool消费者-生产者启动类
package com.ljq.disruptor; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.IgnoreExceptionHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.WorkerPool; public class WorkPoolMain {
public static void main(String[] args) throws InterruptedException {
// 指定 ring buffer字节大小,必需为2的N次方(能将求模运算转为位运算提高效率 ),否则影响性能
int bufferSize = 1024;
//固定线程数
int nThreads = 4; //RingBuffer. createSingleProducer创建一个单生产者的RingBuffer
RingBuffer<TradeEvent> ringBuffer = RingBuffer.createSingleProducer(new EventFactory<TradeEvent>() {
public TradeEvent newInstance() {
return new TradeEvent(UUID.randomUUID().toString());
}
}, bufferSize); SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); WorkerPool<TradeEvent> workerPool = new WorkerPool<TradeEvent>(ringBuffer, sequenceBarrier,
new IgnoreExceptionHandler(), new TradeEventHandler()); //创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
ExecutorService executors = Executors.newFixedThreadPool(nThreads);
workerPool.start(executors); // 生产10个数据
for (int i = 0; i < 80000; i++) {
long seq = ringBuffer.next();
ringBuffer.get(seq).setPrice(i);
ringBuffer.publish(seq);
} Thread.sleep(1000); //等上1秒,等消费都处理完成
workerPool.halt(); //通知事件(或者说消息)处理器 可以结束了(并不是马上结束!!!)
executors.shutdown();
}
}
EventProcessor与WorkPool用法--可处理多消费者的更多相关文章
- Disruptor框架EventProcessor和Workpool的使用
场景使用: 在HelloWorld的实例中,我们创建Disruptor实例,然后调用getRingBuffer方法去获取RingBuffer,其实在很多时候,我们可以直接使用RingBuffer,以及 ...
- Disruptor框架中生产者、消费者的各种复杂依赖场景下的使用总结
版权声明:原创作品,谢绝转载!否则将追究法律责任. Disruptor是一个优秀的并发框架,可以实现单个或多个生产者生产消息,单个或多个消费者消息,且消费者之间可以存在消费消息的依赖关系.网上其他博客 ...
- Disruptor快速入门
在JDK的多线程与并发库一文中, 提到了BlockingQueue实现了生产者-消费者模型 BlockingQueue是基于锁实现的, 而锁的效率通常较低. 有没有使用CAS机制实现的生产者-消费者? ...
- Java编程的逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Streams:深入剖析Redis5.0全新数据结构
Streams:深入剖析Redis5.0全新数据结构 原创: 阿飞的博客 Redis 5.0 全新的数据类型:streams,官方把它定义为:以更抽象的方式建模日志的数据结构.Redis的st ...
- Python生产者producer和consumer消费者案例写法,含有多线程,包含队列queue、JoinableQueue队列的用法
import timeimport random import queuefrom multiprocessing import Process,Queue 案例一:def consumer(q,na ...
- 通过消费者和生产者的多线程程序,了解Java的wait()和notify()用法
仓库类 public class Store { private int size = 0;//当前容量 private final int MAX = 10;//最大容量 //向仓库中增加货物 pu ...
- JUC 并发编程--02,生产者和消费者 synchronized的写法 , juc的写法. Condition的用法
synchronized的写法 class PCdemo{ public static void main(String[] args) { //多个线程操作同一资源 Data data = new ...
- 【源码】RingBuffer(二)——消费者
消费者如何读取数据? 前一篇是生产者的处理,这一篇讲消费者的处理 我们都知道,消费者无非就是不停地从队列中读取数据,处理数据.但是与BlockedQueue不同的是,RingBuffer的消费者不会对 ...
随机推荐
- Visual Studio 2017快捷键
作者:tongqingliu 转载请注明出处:http://www.cnblogs.com/liutongqing/p/7048639.html Visual Studio 2017快捷键 Ctrl+ ...
- 20169207《Linux内核原理及分析》第十二周作业
本周选做的信息安全实验为Python实现Zip文件的暴力破解 实验预备: 这次实验我们需要用到的库为zipfile.下来我们先来了解一下这个模块. 首先我们的重点是对zip文件的操作,而zipfile ...
- bootstrap2.2登录验证
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- Linked List
链表是线性表的一种.线性表是最基本,最简单也是最常见的一种数据结构.线性表中数据元素之间的关系是一对一的关系,除了第一个和最后一个数据元素外,其他数据元素都是首尾相接的. 线性表有两种存储方式,一种是 ...
- MySQL表名大小写设置
1 简介 在MySQL中,数据库对应数据目录中的目录.数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎).因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小 ...
- [控件]unigui移动端下Unidatepicker时间显示解决方案
[控件]unigui移动端下Unidatepicker时间显示解决方案 http://tz10000.com/kong-jian-unigui-yi-dong-duan-xia-unidatepick ...
- cxGrid控件过滤排序和TClientDataSet同步
https://www.cnblogs.com/false/archive/2013/02/24/2924240.html procedure TReport10Form.cxGridViewData ...
- node.js fs,http
error: EventEmitter定义了一个特殊的时间error,它包含了‘错误’的语义,当error被发射时,EventEmitter规定如果没有 响应的监听器,Node.js会把它当做异常,退 ...
- socket粗解
百度定义:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket通信流程: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一 ...
- Swift5 语言参考(八) 模式
模式表示单个值或复合值的结构.例如,元组的结构是两个元素的逗号分隔列表.因为模式表示值的结构而不是任何一个特定值,所以可以将它们与各种值匹配.例如,模式匹配元组和任何其他两元素元组.除了将模式与值匹配 ...