Skywalking源码分享之ReadWriteSafeCache

在L2聚合后要落库的过程中,有一个读写安全缓存,所以简单分析一下:

 /**
     * Pointer of read buffer.
     */
    private volatile BufferedData<T> readBufferPointer;
    /**
     * Pointer of write buffer.
     */
    private volatile BufferedData<T> writeBufferPointer;
    /**
     * Read/Write lock.
     */
    private final ReentrantLock lock;

    /**
     * Build the Cache through two given buffer instances.
     *
     * @param buffer1 read/write switchable buffer
     * @param buffer2 read/write switchable buffer. It is the write buffer at the beginning.
     */
    public ReadWriteSafeCache(BufferedData<T> buffer1, BufferedData<T> buffer2) {
        readBufferPointer = buffer1;
        writeBufferPointer = buffer2;
        lock = new ReentrantLock();
    }

    /**
     * Write the into the {@link #writeBufferPointer} buffer.
     *
     * @param data to enqueue.
     */
    public void write(T data) {
        lock.lock();
        try {
            writeBufferPointer.accept(data);
        } finally {
            lock.unlock();
        }
    }

    /**
     * Write the collection of data into the {@link #writeBufferPointer} buffer.
     *
     * @param data to enqueue.
     */
    public void write(List<T> data) {
        lock.lock();
        try {
            data.forEach(writeBufferPointer::accept);
        } finally {
            lock.unlock();
        }
    }

    public List<T> read() {
        lock.lock();
        try {
            // Switch the read and write pointers, when there is no writing.
            BufferedData<T> tempPointer = writeBufferPointer;
            writeBufferPointer = readBufferPointer;
            readBufferPointer = tempPointer;
        } finally {
            lock.unlock();
        }
        // Call read method outside of write lock for concurrency read-write.
        return readBufferPointer.read();
    }

可以看到有两个指向,一个是读缓存一个是写缓存,并不是单纯的两个指针(即两者指向的对象不同),并发情况下用volatile修饰保证可见性;

可以看到读写都需要抢锁,并且都是独占式,但是明显读更快,因为读方法在加锁的范围内只进行了指向的交换,并且读是一个拿出数据并清除缓存的过程(相当于取,即只取一次);

前提是读请求定时执行,不存在竞争,因此只需要保证读写两者不冲突即可;

 public List<METRICS> read() {
        try {
            return buffer.values().stream().collect(Collectors.toList());
        } finally {
            buffer.clear();//读完即清除,保证只被读取一次
        }
    }

这才是交换指向的意义,举个例子:
1.加锁 写空集合 释放锁
2 加锁 追加写 释放锁
3 加锁 交换指针(读有内容) 释放锁 读 清除内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值