Disruptor
定义:
1.Disruptor叫无锁、高并发、环形Buffer
2.直接覆盖旧数据,降低GC频率,用于生产者和消费者模式;
3.观察者模式:消费者观察队列里边有没有东西,有的话立马拿出来消费
核心:
核心是一个环形的buffer
等待策略:
原理:生产者多,消费者来不及消费,生产者生产的就会执行等待策略
等待策略有8种,常用的是BlockingWait
消费者异常处理:
默认:disruptor.setDefaultExceotionHandle()
覆盖:disruptor.handleExceptionsFor().with()
disruptor.handleExceptionsFor(消费者).with(new ExceptionHandle<LongEvent>(){
1.handleEventException 异常的时候直接打印出来
2.handleOnStartException 启动的时候出异常
3.handleOnshutdownException 停止的时候出异常
})
ConcurrentLinkedQueue 与 Disruptor对比
ConcurrentLinkedQueue:
1.里边是一个个链表,遍历起来没有数组快;
2.维护一个head和end指针,头部加的时候需要枷锁,尾部取得时候也需要加锁;
Disruptor:
1.环形长度为2的n次幂;
2.维护一个位置Sequence,指向下一个可用的元素
3.位置计算:用那个放入的数除以我们整个容量求余就可以,类似于麻将摇色子;
Disruptor开发步骤
1.定义Event-队列中要处理的元素;
2.定义Event工厂,用于填充队列;
1.MyEventFactory实现EventFactiry<LongEvent>接口,重写newInstance方法,直接new LongEvent;
2.工厂的作用:Disruptor初始化的时候会调用Event工厂,对ringBuffer进行内存的预分配,GC频率会降低;
Disruptor disruptor = new Disruptor<>(factory,buffersize,Exccutors.defaultThreadFactory);
disruptor.handEventswith(new MyEventHandler());
disruptor.start();
RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
-------------------------------------------
Long sequence = disruptor.next();
LongEvent event = ringBuffer.get(sequence);
event.set(8888L);
ringBuffer.publish(sequence);
-------------------------------------------
EventTranslator<LongEvent> translator1 = new EventTranslator<LongEvent>(){
@override
public void translateTo(LongEvent event,long sequence){
event.set(8888L);
}
};
ringBuffer.publishEvent(translator1);
-------------------------------------------
EventTranslatorOneAge<LongEvent,Long> translator2 = new EventTranslator<LongEvent,Long>(){
@override
public void translateTo(LongEvent event,long sequence,long l){
event.set(l);
}
};
ringBuffer.publishEvent(translator2,7777L);
-------------------------------------------
EventTranslatorOneAge<LongEvent,Long,Long> translator3 = new EventTranslator<LongEvent,Long,Long>(){
@override
public void translateTo(LongEvent event,long sequence,long l1,long l2){
event.set(l1+l2);
}
};
ringBuffer.publishEvent(translator3,7777L,7777L);
-------------------------------------------
ringBuffer.publishEvent((event,sequence) -> (event.set(7777L)));
ringBuffer.publishEvent((event,sequence,l) -> (event.set(l),7777L));
ringBuffer.publishEvent((event,sequence,l1,l2) -> (event.set(l1+l2),7777L,7777L));
3.定义EventHandler(消费者),处理容器中的元素;
ProducerType生产者线程模式
有两种模式:
1.product.MULTI(默认),多线程,多线程处理是要加锁的;
2.product.SINGLE,单线程,假如只有一个线程,应该把生产者定义为SINGLE,效率高,因为他不加锁;
等待策略 WaitStrateg
八种等待策略:
1.BlockingWaitStrategy(常用):
通过线程堵塞方式,等待生产者唤醒,被唤醒后,在循环检查依赖的Sequence是否已经消费;
2.BusySpinWaitStrategy:
线程一直自旋等待,可能比较消耗CUP;
3.LiteBlockingWaitStratege:
线程阻塞等待生产者唤醒,与BlockingWaitStrategy相比,区别在SignalNeeded.getAndSet,如果两个线程同时访问一个访问waitfor,一个访问signalALL时,可以减少LOCK加锁次数;
4.LiteTimeoutBlockingWaitStrategy:
与LiteBlockingWaitStratege相比,设置了阻塞时间,超过时间后抛出异常;
5.PhasedBackoffWaitStrategy:
根据时间参数和传入的等待策略来决定使用哪种等待策略
6.TimeoutBlockingWaitStrategy:
相比BlockingWaitStrategy相比,设置了阻塞时间,超过时间后抛出异常;
7.YieldingWaitStrategy(常用):
尝试100次,然后Thread,yield()让出CUP;
8.SleepingWaitStrategy(常用):
sleep;
BlockingWaitStrategy满了就等着;
SleepingWaitStrategy满了就睡一觉,醒了看能不能继续执行
;
YieldingWaitStrategy让出CUP,让消费者赶紧消费,消费完了之后再回来看能不能在继续执行生产了;
一般YieldingWaitStrategy效率是最高的;
消费者异常处理
上边已总结