高性能队列Disruptor

Java SDK 提供了 2 个有界队列:ArrayBlockingQueue 和 LinkedBlockingQueue,它们都是基于 ReentrantLock 实现的,在高并发场景下,锁的效率并不高。
今天我们就介绍一种性能更高的有界队列:Disruptor。

Disruptor 是一款高性能的有界内存队列,Disruptor 性能之高,取决于下面四点,下面我们分别来讲解。

1.内存分配更加合理,使用 RingBuffer 数据结构,数组元素在初始化时一次性全部创建,提升缓存命中率;对象循环利用,避免频繁 GC.

该做法利用局部性原理,时间局部性,空间局部性,cpu缓存就利用了程序局部性原理,cpu从内存中加载数据x时,会将数据x缓存到高速缓存cache中(缓存行),同时还缓存了x周围的数据(连续地址)。这样在访问周围数据时,不用再从内存中填到缓存读取。
ArrayBlockingQueue底层也是采用数组的形式存放元素,E1,E2等元素都是由生产者创建的,创建这些元素的时间基本上都是离散的,所以这些元素的内存地址大概率是不连续了。
这里你可能会问,数组的内存地址不是连续的么?数组是连续的,在里面存放的引用,E1,E2元素元素对象地址不连续。在这里插入图片描述
而Disruptor中的RingBuffer数组中的元素在初始化时是一次性全部创建的,所以这些元素的内存地址大概率是连续的,生产者每publishEvent发布Event时,不会创建Event,而是Event.set修改初始化的Event.也就是说 RingBuffer 创建的 Event 是可以循环利用的,这样还能避免频繁创建、删除 Event 导致的频繁 GC 问题。

2. 能够避免伪共享,提升缓存利用率。

伪共享就是多个cup中缓存同一个缓存行,该缓存行中有多个元素,如果修改一个元素,会使其他cpu缓存了该缓存行无效,使得其他线程访问其他元素不成功,没有很好利用cache.
比如ArrayBlockingQueue当cpu从内存中加载takeindex,会同时将putindex加载进缓存行中,当A入队操作,修改takeindex,会把缓存行写入到内存中,导致其他cpu上的缓存行失效,如果B出队,正要修改呢,缓存行失效,就得重新从内存中加载。造成缓存利用率不高。
但是ArrayBlockingQueue内部使用锁,不可能出现出队入队同时出现的情况。
在这里插入图片描述
使用缓存行填充避免伪共享

3. 采用无锁算法,避免频繁加锁、解锁的性能消耗。

对于入队操作,最关键的要求是不能覆盖没有消费的元素;对于出队操作,最关键的要求是不能读取没有写入的元素。
Disruptor使用索引来入队和出队,比如入队,如果没有足够的空余位置,就出让 CPU 使用权,然后重新计算;反之则用 CAS 设置入队索引。

//生产者获取n个写入位置
do {
  //cursor类似于入队索引,指的是上次生产到这里
  current = cursor.get();
  //目标是在生产n个
  next = current + n;
  //减掉一个循环
  long wrapPoint = next - bufferSize;
  //获取上一次的最小消费位置
  long cachedGatingSequence = gatingSequenceCache.get();
  //没有足够的空余位置
  if (wrapPoint>cachedGatingSequence || cachedGatingSequence>current){
    //重新计算所有消费者里面的最小值位置
    long gatingSequence = Util.getMinimumSequence(
        gatingSequences, current);
    //仍然没有足够的空余位置,出让CPU使用权,重新执行下一循环
    if (wrapPoint > gatingSequence){
      LockSupport.parkNanos(1);
      continue;
    }
    //从新设置上一次的最小消费位置
    gatingSequenceCache.set(gatingSequence);
  } else if (cursor.compareAndSet(current, next)){
    //获取写入位置成功,跳出循环
    break;
  }
} while (true);

4. 支持批量消费,消费者可以无锁方式消费多个消息。

发布了34 篇原创文章 · 获赞 0 · 访问量 1089

猜你喜欢

转载自blog.csdn.net/qq_42634696/article/details/104668622