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的消费者不会对 ...
随机推荐
- Swift: 用Alamofire做http请求,用ObjectMapper解析JSON
跟不上时代的人突然间走在了时代的前列,果然有别样的风景.首先鄙视一下AFNetworking.这个东西实在太难用了.不想封装都不行,要不写一大堆代码. NSURL *URL = [NSURL URLW ...
- android sqlite 模糊查询
正确的做法Cursor cursor = sd.rawQuery("select * from contect where QT_CUSTOM like ?", new Strin ...
- 《mysql必知必会》学习_第9章_20180731_欢
第九章,用正则表达式进行搜索. P52 select prod_name from products where prod_name regexp '1000' order by prod_name; ...
- easyUi DataGrid 显示日期列,时间为空也可,的正常显示,及普通居中列情况
$('#tt').datagrid({ url: '@Url.Content("~/kpi/FindList")', w ...
- OpencvSharp 在WPF的Image控件中显示图像
1.安装OpencvSharp 我使用的是VS2013 社区版,安装OpencvSharp3.0 在线安装方法:进入Tools,打开NuGet的包管理器 搜索Opencv 安装之后就可以使用,无需再做 ...
- 自定义WPF窗体形状
介绍 你好WPF爱好者. 随着WPF等统一API语言的发明,丰富用户界面变得非常容易. 创建丰富的用户界面只是一个想法. 您需要拥有的是创造性思维和最新技术融合. WPF和Expression Ble ...
- MQ的demo
public class WorkTest { @Test public void send() throws Exception{ //获取连接 Connection conn = ...
- [leetcode.com]算法题目 - Same Tree
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- cglib invoke 和 invokeSuper 可用的组合
在深入字节码理解invokeSuper无限循环的原因中,我们理解的cglib的原理和其中一个合理的调用方式.但是这个调用方式是基于类的,对所有实例生效.实际场景中,我们可能只是希望代理某个具体的实例, ...
- 简单理解jQuery中$.getJSON、$.get、$.post、$.ajax用法
在WEB开发中异步请求方式普遍使用,ajax技术减少程序员的工作量,也提升用户交互体验.AJAX的四种异步请求方式都能实现基本需求,闲话不多说,直接切入正题. 1.$.getJSON $.getJSO ...