文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 :
作为Java领域最高性能的 队列,没有之一, 大家不光要懂,而是 需要深入骨髓的搞懂。
所以,给大家奉上了下面的三篇文章,并且配备了视频进行 详细介绍:
作为Java领域最高性能的 队列,没有之一, 大家不光要懂,而是 需要深入骨髓的搞懂。
所以,给大家奉上了下面的三篇文章,并且配备了视频进行 详细介绍:
Disruptor 它可以用来作为高性能的有界内存队列, 适用于两大场景:
生产者消费者场景。Disruptor的最常用的场景就是“生产者-消费者”场景,对场景的就是“一个生产者、多个消费者”的场景,并且要求顺序处理。
备注,这里和JCTool 的 MPSC 队列,刚好相反, MPSC 使用于多生产者,单消费者场景
发布订阅 场景:Disruptor也可以认为是观察者模式的一种实现, 实现发布订阅模式。
当前业界开源组件使用Disruptor的包括Log4j2、Apache Storm等,
Disruptor是一个优秀的并发框架,可以使用在多个生产者单消费者场景
在并发系统中提高性能最好的方式之一就是单一写者原则,对Disruptor也是适用的。
如果在生产者单消费者 需求中仅仅有一个事件生产者,那么可以设置为单一生产者模式来提高系统的性能。
ProducerType 定义了生产者的类型, 两类
在这种场景下,ProducerType 的类型的 SINGLE
参考的代码如下:
执行结果:
以上用例的具体减少,请参见 尼恩《100wqps 日志平台实操,视频》
该场景较为简单,就是多个生产者,单个消费者
其实,消费者也可以是多个
ProducerType 定义了生产者的类型, 两类
在这种场景下,ProducerType 的类型的 MULTI
在代码编写维度,多生产者单消费者场景的要点如下:
创建Disruptor 的时候,将ProducerType.SINGLE改为ProducerType.MULTI,
编写多线程生产者的相关代码即可。
参考的代码如下:
运行的结果如下
以上用例的具体减少,请参见 尼恩《100wqps 日志平台实操,视频》
该场景中,生产者为一个,消费者为多个,多个消费者之间, 存在着竞争关系,
也就是说,对于同一个事件event ,多个消费者 不重复消费
首先,得了解一下,disruptor框架的两个设置消费者的方法
大概有两点:
在disruptor框架调用start方法之前,有两个方法设置消费者:
那么,以上的Disruptor类的handleEventsWith,handleEventsWithWorkerPool方法的联系及区别是什么呢?
相同的在于:
两者共同点都是,将多个消费者封装到一起,供框架消费事件。
第一个不同点在于:
对于某一条事件 event,
handleEventsWith 方法返回的EventHandlerGroup,Group中的每个消费者都会对 event 进行消费,各个消费者之间不存在竞争。
handleEventsWithWorkerPool方法返回的EventHandlerGroup,Group的消费者对于同一条事件 event 不重复消费;也就是,如果c0消费了事件m,则c1不再消费事件m。
另外一个不同:
在设置消费者的时候,Disruptor类的handleEventsWith,handleEventsWithWorkerPool方法所传入的形参不同。对于独立消费的消费者,应当实现EventHandler接口。对于不重复消费的消费者,应当实现WorkHandler接口。
因此,根据消费者集合是否独立消费事件,可以对不同的接口进行实现。也可以对两种接口同时实现,具体消费流程由disruptor的方法调用决定。
执行结果
以上用例的具体减少,请参见 尼恩《100wqps 日志平台实操,视频》
在 多个消费者串行消费场景中,多个消费者,可以按照次序,消费消息。
比如:一个用户注册的Event,需要有一个Handler来存储信息,一个Hanlder来发邮件等等。
先并发,后串行
执行结果
多组消费者形成 并行链,特点是:
链内 串行
链间 并行
执行结果
多组消费者 相互隔离,特点是:
组内 相互竞争
组间 相互隔离
执行结果
多组消费者形成 并行链,特点是:
组内 相互竞争
组之间串行依次执行
组之间串行依次执行,组内有多个实例竞争执行
执行效果
这是一种比较复杂的场景
单边内部是有序的
边和边之间是并行的
@org.junit.Test
public void testHexagonConsumerDisruptorWithMethodRef() throws InterruptedException {
// 消费者线程池
Executor executor = Executors.newCachedThreadPool();
// 环形队列大小,2的指数
int bufferSize = 1024;
// 构造 分裂者 (事件分发者)
Disruptor disruptor = new Disruptor(LongEvent::new, bufferSize,
executor,
ProducerType.SINGLE, //多个生产者
new YieldingWaitStrategy());
EventHandler consumer1 = new LongEventHandlerWithName("consumer 1");
EventHandler consumer2 = new LongEventHandlerWithName("consumer 2");
EventHandler consumer3 = new LongEventHandlerWithName("consumer 3");
EventHandler consumer4 = new LongEventHandlerWithName("consumer 4");
EventHandler consumer5 = new LongEventHandlerWithName("consumer 5");
// 连接 消费者 处理器
// 可以使用lambda来注册一个EventHandler
disruptor.handleEventsWith(consumer1,consumer2);
disruptor.after(consumer1).handleEventsWith(consumer3);
disruptor.after(consumer2).handleEventsWith(consumer4);
disruptor.after(consumer3,consumer4).handleEventsWith(consumer5);
// 开启 分裂者(事件分发)
disruptor.start();
// 获取环形队列,用于生产 事件
RingBuffer ringBuffer = disruptor.getRingBuffer();
//1生产者,并发生产数据
LongEventProducerWithTranslator producer = new LongEventProducerWithTranslator(ringBuffer);
Thread thread = new Thread() {
@Override
public void run() {
for (long i = 0; true; i++) {
producer.onData(i);
ThreadUtil.sleepSeconds(1);
}
}
};
thread.start();
ThreadUtil.sleepSeconds(5);
}
https://blog.csdn.net/hxg117/article/details/78064632
http://openjdk.java.net/projects/jdk8/features
http://beautynbits.blogspot.co.uk/2012/11/the-end-for-false-sharing-in-java.html
http://openjdk.java.net/jeps/142
http://mechanical-sympathy.blogspot.co.uk/2011/08/false-sharing-java-7.html
http://stackoverflow.com/questions/19892322/when-will-jvm-use-intrinsics
https://blogs.oracle.com/dave/entry/java_contented_annotation_to_help
https://www.jianshu.com/p/b38ffa33d64d
https://blog.csdn.net/MrYushiwen/article/details/123171635
https://blog.csdn.net/everyok/article/details/88889057