美文网首页
RingBuffer 缓存如何写?

RingBuffer 缓存如何写?

作者: Double_winter | 来源:发表于2019-06-16 11:29 被阅读0次

需求: 我们经常使用缓存, ringBuffer 缓存 便是常见的一种数据结构。 支持高并发。 那问题来了,我们如何写个不错的ringBuffer 出来呢?

写ringbuffer 之前需要理解下下面几个点:

前提: 1.  原子变量如何保证线程安全? 比如 AtomicLong,  AtomicInteger,其原子性操作,such as:  updateAndGet(LongUnaryOperator updateFunction), 虽然updateFunction 是一个表达式,但是整个操作都是原子性质的。 具体如何保证,我也没详细研究。

         2.  尽量使用位移来操作, 加快速度, 比如 &, >>, << 等

          2. 伪共享,为什么会用到这个呢?  其实它跟CPU 缓存有关系,叫做 缓存行(cache line)。一般是64字节,需要8Long 整形的数据来填充。

缓存行 状态图 如下: 

好了,那么我们看看 ringBuffer 是什么样子的:

tail 指针:

表示Producer生产的最大序号(此序号从0开始,持续递增)。Tail不能超过Cursor,即生产者不能覆盖未消费的slot。当Tail已赶上cursor.

cursor指针:

表示Consumer消费到的最小序号(序号序列与Producer序列相同)。Cursor不能超过Tail,即不能消费未生产的slot。当Cursor已赶上tail。

那我们怎么实现这样的数据结构呢?

我们发现会有两个不同的线程(至少), 一个是不断的put 缓存内容,一个是不断take 缓存内容。 如果我们缓存的内容是一个Long 整型的数。

其实这个ringBuffer它就是个数组,由于数组元素在内存中是连续分配的,可以利用CPU cache来提升性能, 但是就会带来上面所说的伪共享的问题。解决的方式就是cache line 补齐的方式。

第一:

定义二个long数组: slot[],存数据,flag[] 数组

定义两个指针:     tail 指针, cursor 指针, 都是原子long整型的。初始化都是-1L

put 操作:使用synchronized

1. 获取 tail 指针现在的value

2. 计算下一个 tail 执政的value 是多少

3. 将slots[] 赋上缓存的值,flags 做个 “can take flag”

4. tail 指针 加上一

第二:

take 缓存数据的 操作:

1. 获取cursor 指针现在的value

2. 和tail 只能value 比较,如果等于 tail 的value,表示 cursor 指针追赶到tail 指针,此时ringbuffer 是empty的。

3. 计算下一个slot[] 的index 是多少,获取值就可以了。

请记住 tail , cursor是long 原子整型, 他们是无限增加的,但是 

第三:

cache line 补齐的方式:

,我们知道一条缓存行有 64 字节,而 Java 程序的对象头固定占 8 字节(32位系统)或 12 字节( 64 位系统默认开启压缩, 不开压缩为 16 字节),所以我们只需要填 6 个无用的长整型补上6*8=48字节,让不同的 VolatileLong 对象处于不同的缓存行,就避免了伪共享( 64 位系统超过缓存行的 64 字节也无所谓,只要保证不同线程不操作同一缓存行就可以)。

可以继承 AtomicLong, 子类里面定义6个Long 整型的,就可以避免伪共享的问题。

RingBuffer 确实不好写,我觉得,而且里面的操作都是以位移为多数,不好弄。但是搞好,速度会很快的。自己水平不行,记录ringbuffer 大概操作过程,以后用的着。

相关文章

  • RingBuffer 缓存如何写?

    需求: 我们经常使用缓存, ringBuffer 缓存 便是常见的一种数据结构。 支持高并发。 那问题来了,我们如...

  • 3. Disruptor核心组件

    1.RingBuffer、Disruptor RingBuffer: 基于数组的缓存实现,也是创建Sequence...

  • Disruptor深度解析-RingBuffer

    前言 RingBuffer是Disruptor框架负责数据存储的模块,大部分文章也将其称之为环形缓存区,本文将对其...

  • RingBuffer

    在阅读sofaJraft的代码时候,有一个Disruptor 框架,可以非常高性能的处理produce-consu...

  • 并发编程之Disruptor-1.核心简介

    1.简介 DIsruptor核心-RIngBuffer、Disroptor Disruptor核心-Sequenc...

  • 并发编程之Disruptor-2.核心介绍

    1.Disruptor核心组件 RingBuffer Sequence Sequencer Sequence Ba...

  • 如何写缓存文档

    在一个工程里面,除了要撰写必要的api文档之外,还需要对其他的数据结构进行描述,而缓存文档就是其中之一。 在我的工...

  • Disruptor:高性能的生产者-消费者的无锁实现

    Disruptor: 在Disruptor中使用环形队列RingBuffer来代替普通的线性队列(内部实现是普通的...

  • 循环缓冲区(RingBuffer)

    一、简介 1、循环缓冲区的实现原理 环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指...

  • 循环缓冲区RingBuffer

    stm32和外设通信的时候,需要对外设发来的串行数据做同步。参考过下面这个链接的方法:串口通信帧的同步方法(识别一...

网友评论

      本文标题:RingBuffer 缓存如何写?

      本文链接:https://www.haomeiwen.com/subject/yspwfctx.html