前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无锁RingBuffer浅析

无锁RingBuffer浅析

作者头像
随心助手
发布2022-11-30 14:08:00
6220
发布2022-11-30 14:08:00
举报
文章被收录于专栏:nginx遇上redisnginx遇上redis

RingBuffer是环形缓冲区,支持读和写两种操作,相似于循环队列。在实现上,通常用数组存储数据,同时设置双指针head和tail,head指向队首,tail指向队尾。读数据时,head++;写数据时,tail++。显然,RingBuffer不是线程安全的,需要对读写数据进行同步。然而,有一种特殊状况:一个线程读,一个线程写,在这种状况下能够实现线程安全的无锁RingBuffer,代码以下:

import java.util.Arrays;

public class RingBuffer<T> {

private final static int DEFAULT_SIZE = 1024;

private Object[] buffer;

private int head = 0;

private int tail = 0;

private int bufferSize;

public RingBuffer(){

this.bufferSize = DEFAULT_SIZE;

this.buffer = new Object[bufferSize];

}

public RingBuffer(int initSize){

this.bufferSize = initSize;

this.buffer = new Object[bufferSize];

}

private Boolean empty() {

return head == tail;

}

private Boolean full() {

return (tail + 1) % bufferSize == head;

}

public void clear(){

Arrays.fill(buffer,null);

this.head = 0;

this.tail = 0;

}

public Boolean put(String v) {

if (full()) {

return false;

}

buffer[tail] = v;

tail = (tail + 1) % bufferSize;

return true;

}

public Object get() {

if (empty()) {

return null;

}

Object result = buffer[head];

head = (head + 1) % bufferSize;

return result;

}

public Object[] getAll() {

if (empty()) {

return new Object[0];

}

int copyTail = tail;

int cnt = head < copyTail ? copyTail - head : bufferSize - head + copyTail;

Object[] result = new String[cnt];

if (head < copyTail) {

for (int i = head; i < copyTail; i++) {

result[i - head] = buffer[i];

}

} else {

for (int i = head; i < bufferSize; i++) {

result[i - head] = buffer[i];

}

for (int i = 0; i < copyTail; i++) {

result[bufferSize - head + i] = buffer[i];

}

}

head = copyTail;

return result;

}

}

为何上述代码可以确保线程安全?能够看到,建立RingBuffer后,只有写线程修改tail,只有读线程修改head,而且始终只有一个读线程,一个写线程,所以是没有并发写操作的。然而,因为读操做和写操做都不是原子性的,有可能读操做发生在写操做的过程当中,写操做发生在读操做的过程当中。这样会致使如下两个问题:安全

  • 对于读操作,当RingBuffer为空时,有可能读到还没写的数据。
  • 对于写操作,当RingBuffer为满时,有可能写到还没读的数据。

可是,对于写操作,咱们是先修改elements,再修改tail;对于读操作,咱们是先修改elements,再修改head。所以上述两个问题是不存在的,咱们说上述RingBuffer是线程安全的,而且是无锁的,具备较高的性能。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 nginx遇上redis 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档