单一的生产者,消费者有多个,使用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用法--可处理多消费者的更多相关文章

  1. Disruptor框架EventProcessor和Workpool的使用

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

  2. Disruptor框架中生产者、消费者的各种复杂依赖场景下的使用总结

    版权声明:原创作品,谢绝转载!否则将追究法律责任. Disruptor是一个优秀的并发框架,可以实现单个或多个生产者生产消息,单个或多个消费者消息,且消费者之间可以存在消费消息的依赖关系.网上其他博客 ...

  3. Disruptor快速入门

    在JDK的多线程与并发库一文中, 提到了BlockingQueue实现了生产者-消费者模型 BlockingQueue是基于锁实现的, 而锁的效率通常较低. 有没有使用CAS机制实现的生产者-消费者? ...

  4. Java编程的逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  5. Streams:深入剖析Redis5.0全新数据结构

    Streams:深入剖析Redis5.0全新数据结构   原创: 阿飞的博客   Redis 5.0 全新的数据类型:streams,官方把它定义为:以更抽象的方式建模日志的数据结构.Redis的st ...

  6. Python生产者producer和consumer消费者案例写法,含有多线程,包含队列queue、JoinableQueue队列的用法

    import timeimport random import queuefrom multiprocessing import Process,Queue 案例一:def consumer(q,na ...

  7. 通过消费者和生产者的多线程程序,了解Java的wait()和notify()用法

    仓库类 public class Store { private int size = 0;//当前容量 private final int MAX = 10;//最大容量 //向仓库中增加货物 pu ...

  8. JUC 并发编程--02,生产者和消费者 synchronized的写法 , juc的写法. Condition的用法

    synchronized的写法 class PCdemo{ public static void main(String[] args) { //多个线程操作同一资源 Data data = new ...

  9. 【源码】RingBuffer(二)——消费者

    消费者如何读取数据? 前一篇是生产者的处理,这一篇讲消费者的处理 我们都知道,消费者无非就是不停地从队列中读取数据,处理数据.但是与BlockedQueue不同的是,RingBuffer的消费者不会对 ...

随机推荐

  1. 手把手教Electron+vue的使用

    .现如今前端框架数不胜数,尤其是angular.vue吸引一大批前端开发者,在这个高新技术快速崛起的时代,自然少不了各种框架的结合使用.接下来是介绍electron+vue的结合使用. 2.Elect ...

  2. Chapter15 Principles of Metabolic Regulation

    15.1 调节代谢的通路 (1)细胞和有机体维持着动态稳定 调节作用的基因多 2500个 12% 激酶占比多 300个 一个通路受到多方调节 (2)酶的数量和催化活性 可以被调节 反应物的调控 糖酵解 ...

  3. 模块import,from ..import...

    首次导入模块发生3件事 1.创建一个模块的名称空间 2.执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中 3.在当前执行文件中直接拿到一个名字,该名字就是执行模块中相对应的名字 f ...

  4. Kotlin, Android的Swift

    Kotlin, Android的Swift 苹果已经用Swift代替Objective-C,一种古老的语言,来进行iOS的开发了.明显Android开发也有这个趋势. 虽然现在已经可以选择Scala或 ...

  5. day30(对象转json(java))

    转换之前需要知道什么是json json类似于map集合:键值对的方式存在,是一种轻量级数据交互格式. eg: {name:" ",age:15} [{name:" &q ...

  6. 使用Servlet动态生成验证码

    最近在重新看了一遍servlert,看到篇优质博客推荐给大家:https://www.cnblogs.com/xdp-gacl/p/3798190.html 顺便把学习过程中的知识记录下来. 今天是如 ...

  7. Java关键字、标识符、表达式、常用符号

    关键字 包:package(包).import(导入) 类:class(类).enum(枚举).interface(接口).extends(继承).implements(实现) 方法:void(空). ...

  8. ASP.NET Web API 框架研究 Controller创建 HttpController 类型解析 选择 创建

    上一篇介绍了HttpController的一些细节,接下来说下HttpController 类型解析.选择和创建.生产HttpController实例的生产线如下图: 一.涉及的类及源码分析 涉及的类 ...

  9. .Net Core Web应用发布至IIS后报“An error occurred while starting the application”错误

    An error occurred while starting the application. .NET Core X64 v4.1.1.0    |   Microsoft.AspNetCore ...

  10. mysql-5.7安装、配置

    1.进入到要存放安装包的位置 cd /home/lnmp 2.查看系统中是否已安装 MySQL 服务,以下提供两种方式: rpm -qa | grep mysql yum list installed ...