背景
在语音开发中经常需要补偿音频,使用普通的队列来保存音频如果没有停止写的话很容易内存被撑爆,然后普通队列取最新的一段数据也不方便,这时候环形缓冲区就派上用场了。
实际上org.apache.commons.collections4提供了环形缓冲区实现CircularFifoQueue.java。
因为开始也不知道有三方库实现了,所以算自己写了个,比较简单的实现。
代码实现
/**
* 环形缓冲区
*/
public class CycleQueue {
private VoiceByte[] arr;
private int maxSize;// 最大空间
private int len;// 有效长度
private int end;// 队尾
private boolean isFull;
public CycleQueue(int size) {
this.maxSize = size;
this.arr = new VoiceByte[maxSize];
this.len = 0;
this.end = -1;
this.isFull = false;
}
/**
* 生产数据
*
* @param voiceBytes
*/
public synchronized void produce(VoiceByte voiceBytes) {
//如果满了
if (end == maxSize - 1) {
isFull = true;
end = -1;
}
arr[++end] = voiceBytes;
if (len < maxSize) {
len++;
} else {
len = maxSize;
}
}
/**
* 生产数据
*
* @param bytes
*/
public synchronized void produce(byte[] bytes) {
VoiceByte voiceByte = new VoiceByte(bytes);
produce(voiceByte);
}
/**
* 消费所有数据
*
* @return
*/
public synchronized List<VoiceByte> consumeAll() {
List<VoiceByte> list = getAllVoiceBytes();
this.len = 0;
this.end = -1;
this.isFull = false;
return list;
}
private List<VoiceByte> getAllVoiceBytes() {
List<VoiceByte> list = new ArrayList<>();
List<VoiceByte> queueData = Arrays.asList(arr);
if (isFull) {
list.addAll(queueData.subList(end + 1, maxSize));
list.addAll(queueData.subList(0, end + 1));
} else {
if (len > 0) {
list.addAll(queueData.subList(0, len));
}
}
return list;
}
/**
* 判断是否为空
*
* @return
*/
public boolean isEmpty() {
return (len == 0);
}
/**
* 判断是否满了
*
* @return
*/
public boolean isFull() {
return (len == maxSize);
}
/**
* 获得队列的有效长度
*
* @return
*/
public int size() {
return len;
}
public synchronized void clear() {
Arrays.fill(arr, null);
this.len = 0;
this.end = -1;
this.isFull = false;
}
}
/**
* byte数组封装类
*/
public static class VoiceByte {
public byte[] localBytes;
public VoiceByte(byte[] bytes) {
localBytes = bytes;
}
public int size() {
return localBytes.length;
}
}