41 - 案例分析(三):高性能队列Disruptor

  我们在《24 - 并发容器》介绍过 Java SDK 提供了 2 个有界队列:ArrayBlockingQueue 和 LinkedBlockingQueue,它们都是基于 ReentrantLock 实现的,在高并发场景下,锁的效率并不高,那有没有更好的替代品呢?有,今天我们就介绍一种性能更高的有界队列:Disruptor。

  

  Disruptor 是一款高性能的有界内存队列,目前应用非常广泛,Log4j2、Spring Messaging、HBase、Storm 都用到了 Disruptor,那 Disruptor 的性能为什么这么高呢?Disruptor 项目团队曾经写过一篇论文,详细解释了其原因,可以总结为如下:

  1. 内存分配更加合理,使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;
  2. 对象循环利用,避免频繁 GC。能够避免伪共享,提升缓存利用率;
  3. 采用无锁算法,避免频繁加锁、解锁的性能消耗;
  4. 支持批量消费,消费者可以无锁方式消费多个消息。

  其中,前三点涉及到的知识比较多,所以今天咱们重点讲解前三点,不过在详细介绍这些知识之前,我们先来聊聊 Disruptor 如何使用,好让你先对 Disruptor 有个感官的认识。

  

  下面的代码出自官方示例,我略做了一些修改,相较而言,Disruptor 的使用比 Java SDK 提供 BlockingQueue 要复杂一些,但是总体思路还是一致的,其大致情况如下:

  • 在 Disruptor 中,生产者生产的对象(也就是消费者消费的对象)称为 Event,使用 Disruptor 必须自定义 Event,例如示例代码的自定义 Event 是 LongEvent;
  • 构建 Disruptor 对象除了要指定队列大小外,还需要传入一个 EventFactory,示例代码中传入的是LongEvent::new;
  • 消费 Disruptor 中的 Event 需要通过 handleEventsWith() 方法注册一个事件处理器,发布 Event 则需要通过 publishEvent() 方法。
public class TestDisruptor {
   

    public static void main(String[] args) {
   
        // 指定RingBuffer大小, 必须是2的N次方
        int bufferSize = 1024;

        //构建Disruptor
        Disruptor<LogEvent> disruptor
                = new Disruptor<>(LogEvent::new, bufferSize, 
                	DaemonThreadFactory.INSTANCE);

        //注册事件处理器
        disruptor.handleEventsWith((event, sequence, endOfBatch) -> 
        {
   
            System.out.println("event: " + event.getValue() 
            + ", sequence: " + sequence + ", endOfBatch: " 
            + endOfBatch);
        });

        //启动Disruptor
        disruptor.start();

        // 获取RingBuffer
        RingBuffer<LogEvent> ringBu
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值