JAVA高性能有界内存队列-Disruptor 简介及使用示例

1.Disruptor简介      

        Disruptor是一个高性能的有界内存队列,它在 Apache Storm、Camel、Log4j 2 等很多知名项目中都有广泛应用。之所以如此受青睐,主要还是因为它的性能表现非常优秀。它比 Java 中另外一个非常常用的内存消息队列 ArrayBlockingQueue(ABS)的性能,要高一个数量级,可以算得上是最快的内存消息队列了。它还因此获得过 Oracle 官方的 Duke 大奖。

Disruptor 是如何做到如此高性能的?

  • 使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;对象循环利用,避免频繁 GC。此外根据Index进行环形定位并非简单取模,而是使用位运算,效率更高,定位更快。
  • 前后56字节(7个long)缓存行填充的手法,使得每个变量独占一个缓存行,避免伪共享,提升CPU缓存利用率。
  • 采用CAS无锁算法,避免频繁加锁、解锁的性能消耗。

伪共享

由于共享缓存行导致缓存无效的场景。

  • 伪共享和 CPU 内部的 Cache 有关,Cache 内部是按照缓存行(Cache Line)管理的,缓存行的大小通常是 64 个字节。CPU 的缓存就利用了程序的局部性原理:时间局部性(指的是程序中的某条指令一旦被执行,不久之后这条指令很可能再次被执行;如果某条数据被访问,不久之后这条数据很可能再次被访问。)、空间局部性(指某块内存一旦被访问,不久之后这块内存附近的内存也很可能被访问)。
  • 为了更好地利用缓存,我们必须避免伪共享,解决手法为:前后56字节(7个long)缓存行填充。

CAS

比较并交换(CompareAndSwap),本质上是无锁,不过也称之为自旋锁或者自旋。

2.使用简单示例

  • 生产者生产的对象(也就是消费者消费的对象)称为 Event,使用 Disruptor 必须自定义 Event。
  • 构建 Disruptor 对象除了要指定队列大小外,还需要传入一个 EventFactory。
  • 消费 Disruptor 中的 Event 需要通过 handleEventsWith() 方法注册一个事件处理器,发布 Event 则需要通过 publishEvent() 或publish()方法。
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

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

/**
 * 单生产者单消费者示例
 */
public class SimpleTest {
    public static void main(String[] args) {
        Executor executor = Executors.newCachedThreadPool();
        LongEventFactory longEventFactory = new LongEventFactory();
        int bufferSize = 256;
        Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(longEventFactory, bufferSize, executor, ProducerType.SINGLE, new BlockingWaitStrategy());
        disruptor.handleEventsWith(new LongEventHandler());
        disruptor.start();

        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
        for (int x = 0; x < 256; x++) {
            long sequence = ringBuffer.next();
            try {
                LongEvent event = ringBuffer.get(sequence);
                event.setValue(x);
            } finally {
                ringBuffer.publish(sequence);
            }
        }
    }

    static class LongEvent {
        private long value;

        public long getValue() {
            return value;
        }

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

    static class LongEventFactory implements EventFactory<LongEvent> {
        @Override
        public LongEvent newInstance() {
            return new LongEvent();
        }
    }

    static class LongEventHandler implements EventHandler<LongEvent> {
        @Override
        public void onEvent(LongEvent longEvent, long sequence, boolean endOfBatch) throws Exception {
            System.out.println("Event:" + longEvent.getValue() + ", sequence: " + sequence);
        }
    }
}
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

import java.util.concurrent.Executors;

/**
 * 多生产者多消费者示例
 */
public class MultiTest {
    public static void main(String[] args) {
        Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(
                new LongEventFactory(),
                getRingBufferSize(500),
                Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()),
                ProducerType.MULTI, // ProducerType.SINGLE  单生产者; ProducerType.MULTI   多生产者
                // BlockingWaitStrategy:最低效的策略,但对CPU的消耗最小;
                // SleepingWaitStrategy:与BlockingWaitStrategy类似,合用于异步日志类似的场景;
                // YieldingWaitStrategy 性能最好,要求事件处理线数小于 CPU 逻辑核心数
                new YieldingWaitStrategy());
        disruptor.handleEventsWithWorkerPool(new LongEventHandler[]{new LongEventHandler("c1"), new LongEventHandler("c2")});
        RingBuffer<LongEvent> ringBuffer = disruptor.start();

        //生产者1
        new Thread(() -> {
            publish(ringBuffer, 0, 10);
        }).start();

        // 生产者2
        new Thread(() -> {
            publish(ringBuffer, 10, 20);
        }).start();
    }

    private static void publish(RingBuffer<LongEvent> ringBuffer, int start, int end) {
        for (int x = start; x < end; x++) {
            long sequence = ringBuffer.next();
            try {
                LongEvent event = ringBuffer.get(sequence);
                event.setValue(x);
            } finally {
                ringBuffer.publish(sequence);
            }
        }
    }

    private static int getRingBufferSize(int num) {
        int s = 2;
        while (s < num) {
            s <<= 1;
        }
        return s;
    }

    static class LongEvent {
        private long value;

        public long getValue() {
            return value;
        }

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

    static class LongEventFactory implements EventFactory<LongEvent> {
        @Override
        public LongEvent newInstance() {
            return new LongEvent();
        }
    }

    static class LongEventHandler implements EventHandler<LongEvent>, WorkHandler<LongEvent> {
        private String consumerId;
        public LongEventHandler(String consumerId){
            this.consumerId = consumerId;
        }

        @Override
        public void onEvent(LongEvent longEvent, long sequence, boolean endOfBatch) throws Exception {
            System.out.println("Event:" + longEvent.getValue() + ", sequence: " + sequence);
        }

        @Override
        public void onEvent(LongEvent longEvent) throws Exception {
            System.out.println(this.consumerId + " consume:" + longEvent.getValue());
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BossFriday

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值