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,而且始终只有一个读线程,一个写线程,所以是没有并发写操作的。然而,因为读操做和写操做都不是原子性的,有可能读操做发生在写操做的过程当中,写操做发生在读操做的过程当中。这样会致使如下两个问题:安全
可是,对于写操作,咱们是先修改elements,再修改tail;对于读操作,咱们是先修改elements,再修改head。所以上述两个问题是不存在的,咱们说上述RingBuffer是线程安全的,而且是无锁的,具备较高的性能。
本文分享自 nginx遇上redis 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!