Java高性能异步处理框架-Disruptor

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

发布了29 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43778179/article/details/103127247