145、disruptor无锁消息队列

disruptor无锁消息队列,使用ringbuffer来实现无锁消息队列

正常多线程访问访问同一个资源的时候是需要进行加锁的,

如synchronized方法。但是使用synchronized方法的时候会使cpu进行等待,

在高并发的情况下会消耗大量的cpu资源。

为了解决这个问题,使用无锁消息队列+共享指针的方式。

解决了多线程访问同一个资源的加锁问题

和多线程之间复制数据导致效率低下的问题(共享指针)

 

 

上图为ringbuffer的数据结构,底层的数据结构为数组结构,

在往ringbuffer中存数据的时候,会使用当前的序号对ringbuffer的大小进行取余数运算

然后在余数的位置index直接使用新的值去覆盖旧的值,这样就避免了垃圾回收的过程。  index小于数组的大小,

在进行消费的时候,

workSequence和sequence。

多个线程共用一个sequence,sequence指向未被消费过的元素的位置。

当生产者往队列里面插入元素的时候,就会判断如果插入元素的位置,大于等于sequence,就不会继续往里面进行插入。

多个线程共用一个workSequence,workSequence指向可以被消费的元素的最大位置。

多个线程竞争序号workSequence   (CAS机制)。

 

 

 

ringbuffer的使用示例,

1、创建一个事件类型。

package com.bjpowernode.consumer;


public class StringEvent {

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }


    private String value;



}

 

2、创建一个事件工厂类。

package com.bjpowernode.consumer;

import com.lmax.disruptor.EventFactory;

/**
 * 定义事件工厂
 */
public class StringEventFactory implements EventFactory<StringEvent> {

    @Override
    public StringEvent newInstance() {
        return new StringEvent();
    }
}

 

 

3、创建一个事件处理类。

package com.bjpowernode.consumer;

import com.lmax.disruptor.EventHandler;

public class StringEventHandler implements EventHandler<StringEvent> {

    public StringEventHandler() {

    }

    @Override
    public void onEvent(StringEvent event,long sequence,boolean endOfBatch) throws  Exception{

        System.out.println("consumer:"+event.getValue()+"--->sequence="+sequence+",endOfBatchc="+endOfBatch);
    }



}

 

 

4、生产者往ringbuffer无锁队列中生产事件。

package com.bjpowernode.provider;

import com.bjpowernode.consumer.StringEvent;
import com.lmax.disruptor.RingBuffer;

public class StringEventProducer {

    /**
     *   核心类环形数组这个类
     */
    public final RingBuffer<StringEvent> ringBuffer;

    /**
     *    通过构造方法初始化环形数组这个核心类
     * @param ringBuffer
     */
    public StringEventProducer(RingBuffer<StringEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    /**
     *    生产事件(数据)的一个方法
     *    其实就是往环形数组里面放数据
     * @param data
     */
    public  void onData(String data){
        /**
         * ringBuffer获取下一个序号*/
        long sequence = ringBuffer.next();
        try{
            /**2、取出空的事件队列*/
            StringEvent stringEvent = ringBuffer.get(sequence);
            /**3、获取事件队列传递的数据*/
            stringEvent.setValue(data);
        }finally {
            /**4、发布事件(把事件放到环形数组里面去)*/
            ringBuffer.publish(sequence);
            System.out.println("producer produce data"+ sequence);
        }
    }
}

 

 

 

5、ringbuffer测试事件的生产与消费。

 

package com.bjpowernode.sample;

import com.bjpowernode.consumer.StringEvent;

import com.bjpowernode.consumer.StringEventFactory;
import com.bjpowernode.consumer.StringEventHandler;
import com.bjpowernode.provider.StringEventProducer;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;


public class Test {

    public static void main(String[] args) {

        ThreadFactory threadFactory = Executors.defaultThreadFactory();

        EventFactory<StringEvent> eventFactory = new StringEventFactory();

        int ringBufferSize = 16;

        Disruptor<StringEvent> disruptor = new Disruptor<StringEvent>(eventFactory,
                ringBufferSize,
                threadFactory,
                ProducerType.SINGLE,
                new YieldingWaitStrategy()
        );

        disruptor.handleEventsWith(new StringEventHandler());

        disruptor.start();

        /**
         *   消费者启动了
         *   -----------------------------------
         *   下面开始生产
         */

        /**
         *   创建RingBuffer容器
         */
        RingBuffer<StringEvent> ringBuffer = disruptor.getRingBuffer();

        /**
         *   创建生产者
         */
        StringEventProducer producer = new StringEventProducer(ringBuffer);

        for (int i = 0; i < 10000; i++) {
            producer.onData(String.valueOf(i));
        }


        /**
         *   关闭disruptor 和 executor
         *
         */
        disruptor.shutdown();
    }


}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值