EventBus:
基于观察者模式实现的,本文基于同步模式来操作;这里只介绍下几个常用操作的代码实现:
register:注册观察者实现:主要就是以把观察者观察的类key,同类观察者的set集合为value构成一个ConcurrenHashMap
代码如下:
private final ConcurrentMap<Class<?>, CopyOnWriteArraySet<Subscriber>> subscribers =
Maps.newConcurrentMap();
这里有两步加锁:map分段锁,copyOnWriteArraySet读写锁;
EventBus.post(Object):发送事件实现:根据事件的class找subscribers中的观察者,通过反射执行所有观察者的@Subscribe注解注释的方法;
代码如下:
public void post(Object event) {
Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
if (eventSubscribers.hasNext()) {
dispatcher.dispatch(event, eventSubscribers);
} else if (!(event instanceof DeadEvent)) {
// the event had no subscribers and was not itself a DeadEvent
post(new DeadEvent(this, event));
}
}
本地测试结果:生产者生成100000条事件非常快(没找到有拒绝策略,异步模式有线程池拒绝),如果动态增加大量生产者效率会下降主要是因为两个锁,另外因为消费者需要轮询执行,如果消费者延迟高,会导致内存和cpu飙升,本地16g内存测试结果:
应用场景:ddd领域模型中jvm事件总线可以使用eventBus,建议使用异步的模式
Disruptor:
基础介绍就不说了自己去看官方文档,这里只写做事件总线怎么做:
生产者:
// 1.ringBuffer 事件队列 下一个槽
long sequence = ringBuffer.next();
//2.取出空的事件队列
LongEvent longEvent = ringBuffer.get(sequence);
data = byteBuffer.getLong(0);
//3.获取事件队列传递的数据
longEvent.setValue(data);
ringBuffer.publish(sequence);
消费者(单线程):把消费者作为事件转发器,根据事件类型转发到不同的自定义事件处理器(类似于Redis的事件处理机制)
每个事件处理器都在各自的业务线程池中执行(Hystrix的线程池隔离机制),避免某个延迟操作影响其他操作(线程池数不宜过多避免达到监控平台的数量限制)
这里为什么把两种方式比较呢?
其实大部分公司eventBus肯定够用,但是他的所有的事件都是一个线程池,并没有隔离,而且还有锁,总的来说就是一个pull的模式。
disruptor是一个拉的模式,ringbuffer和消费者各自维护一个序号,用于记录消费者消费的消费位置;另外disruptor支持多种消费模式:串行,并行(a1,a2之间并行,但是a1,b1需要串行),链式并行,菱形并行模式;
对于支付类的大型公司还是disruptor的无锁效率更高,并且使用事件分派机制可以使各个业务操作在线程池层面隔离
来源:CSDN
作者:头都秃了
链接:https://blog.csdn.net/qq1076472549/article/details/103909282