1、Disruptor 简介
Disruptor 是实现了“队列”的功能,而且是一个有界队列。那么它的应用场景自然就是“生产者-消费者”模型的应用场合了。
2、与BlockingQueue 区别
BlockingQueue 是一个 FIFO 队列,生产者(Producer)往队列里发布(publish)一项事件(或称之为“消息”也可以)时,消费者(Consumer)能获得通知;如果没有事件时,消费者被堵塞,直到生产者发布了新的事件。
这些都是 Disruptor 能做到的,与之不同的是,Disruptor 能做更多:
同一个“事件”可以有多个消费者,消费者之间既可以并行处理,也可以相互依赖形成处理的先后次序(形成一个依赖图);
预分配用于存储事件内容的内存空间;
针对极高的性能目标而实现的极度优化和无锁的设计;
以上的描述虽然简单地指出了 Disruptor 是什么,但对于它“能做什么”还不是那么直截了当。一般性地来说,当你需要在两个独立的处理过程(两个线程)之间交换数据时,就可以使用 Disruptor 。当然使用队列(如上面提到的 BlockingQueue)也可以,只不过 Disruptor 做得更好。
3、使用
事件对象
package com.hsshy.beam.queue.disruptor;
import java.io.Serializable;
/**
* 事件对象(秒杀事件)
* 创建者 科帮网
*/
public class SeckillEvent implements Serializable {
private static final long serialVersionUID = 1L;
private long seckillId;
private long userId;
public SeckillEvent(){
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
}
事件生成工厂(用来初始化预分配事件对象)
package com.hsshy.beam.queue.disruptor;
import com.lmax.disruptor.EventFactory;
/**
* 事件生成工厂(用来初始化预分配事件对象)
* 创建者 科帮网
*/
public class SeckillEventFactory implements EventFactory<SeckillEvent> {
public SeckillEvent newInstance() {
return new SeckillEvent();
}
}
生产者
package com.hsshy.beam.queue.disruptor;
import com.lmax.disruptor.EventTranslatorVararg;
import com.lmax.disruptor.RingBuffer;
/**
* 使用translator方式生产者
* 创建者 科帮网
*/
public class SeckillEventProducer {
private final static EventTranslatorVararg<SeckillEvent> translator = new EventTranslatorVararg<SeckillEvent>() {
public void translateTo(SeckillEvent seckillEvent, long seq, Object... objs) {
seckillEvent.setSeckillId((Long) objs[0]);
seckillEvent.setUserId((Long) objs[1]);
}
};
private final RingBuffer<SeckillEvent> ringBuffer;
public SeckillEventProducer(RingBuffer<SeckillEvent> ringBuffer){
this.ringBuffer = ringBuffer;
}
public void seckill(long seckillId, long userId){
this.ringBuffer.publishEvent(translator, seckillId, userId);
}
}
消费者
package com.hsshy.beam.queue.disruptor;
import com.hsshy.beam.common.utils.SpringContextHolder;
import com.hsshy.beam.queue.service.ISeckillService;
import com.lmax.disruptor.EventHandler;
/**
* 消费者(秒杀处理器)
* 创建者 科帮网
*/
public class SeckillEventConsumer implements EventHandler<SeckillEvent> {
private ISeckillService seckillService = (ISeckillService) SpringContextHolder.getBean("seckillService");
public void onEvent(SeckillEvent seckillEvent, long seq, boolean bool) throws Exception {
seckillService.startSeckil(seckillEvent.getSeckillId(), seckillEvent.getUserId());
}
}
DisruptorUtil工具类
package com.hsshy.beam.queue.disruptor;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import java.util.concurrent.ThreadFactory;
/**
* 来自<tukangzheng>的建议,具体性能待测试
* 创建者 张志朋
* 创建时间 2018年5月23日
*
*/
public class DisruptorUtil {
static Disruptor<SeckillEvent> disruptor = null;
static{
SeckillEventFactory factory = new SeckillEventFactory();
int ringBufferSize = 1024;
ThreadFactory threadFactory = new ThreadFactory() {
public Thread newThread(Runnable runnable) {
return new Thread(runnable);
}
};
disruptor = new Disruptor<SeckillEvent>(factory, ringBufferSize, threadFactory);
disruptor.handleEventsWith(new SeckillEventConsumer());
disruptor.start();
}
public static void producer(SeckillEvent kill){
RingBuffer<SeckillEvent> ringBuffer = disruptor.getRingBuffer();
SeckillEventProducer producer = new SeckillEventProducer(ringBuffer);
producer.seckill(kill.getSeckillId(),kill.getUserId());
}
}
以上代码用到的类 SpringContextHolder
package com.hsshy.beam.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean
*
* @author fengshuonan
* @date 2016年11月27日 下午3:32:11
*/
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
assertApplicationContext();
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
assertApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext();
return applicationContext.getBean(requiredType);
}
private static void assertApplicationContext() {
if (SpringContextHolder.applicationContext == null) {
throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
}
}
}
使用demo 模拟抢购
@ApiOperation(value="秒杀柒(Disruptor队列)",nickname="科帮网")
@PostMapping("/startDisruptorQueue")
public R startDisruptorQueue(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀八(正常)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {
@Override
public void run() {
SeckillEvent kill = new SeckillEvent();
kill.setSeckillId(killId);
kill.setUserId(userId);
DisruptorUtil.producer(kill);
}
};
executor.execute(task);
}
try {
Thread.sleep(10000);
Long seckillCount = seckillService.getSeckillCount(seckillId);
LOGGER.info("一共秒杀出{}件商品",seckillCount);
} catch (InterruptedException e) {
e.printStackTrace();
}
return R.ok();
}
4、多消费者
该博文非常详细:
https://www.cnblogs.com/pku-liuqiang/p/8544700.html
参考链接:
https://gitee.com/52itstyle/spring-boot-seckill
https://www.cnblogs.com/haiq/p/4112689.html
https://www.cnblogs.com/hupengcool/p/4196965.html