import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import hooyee.IDataElement;
/**
* 一个缓存队列,用于管理
* [a[], b[], c[]]形式的数据,从其中取出指定长度的数据,若指定的长度小于队首的可用长度,则返回该队首元素(该元素不出队),并修改该元素的region.
* 若大于队首,则直接返回队首,并将队首元素出队,可用范围是 T 的[startPosition, endPosition)
* @param <T>
*/
public class DataCache<T extends IDataElement> {
private long MAX_SIZE;
private final AtomicLong totalSize = new AtomicLong();
/**
* dataQueue的poll和offer操作也需要保证线程安全,因此变更数据结构
*/
Queue<T> dataQueue = new ConcurrentLinkedQueue<>();
/**
* offer和poll需要通过overflow来确认,而overflow又依赖于updateSize,因此需要保证poll和offer的整个流程的原子性(其实只要保证offer,因为poll是会减小他的值,这样只会更加满足条件)
**/
private final ReentrantLock pollLock = new ReentrantLock();
private final ReentrantLock offerLock = new ReentrantLock();
public DataCache() {
MAX_SIZE = 1024 * 1024 * 4;
}
public DataCache(long maxSize) {
MAX_SIZE = maxSize;
}
/**
* 线程安全的, 只用于T为 IElement的时候,若不是与不带参的效果一样
* @param length 从队列的第一个元素中获取指定长度的数据,如果第一个元素小于改长度,调用poll,若大于则调用peek,并移动offset等信息
* @return
*/
public @Nullable T poll(int length) {
pollLock.lock();
try {
T data = dataQueue.peek();
if (data != null) {
removeIfOver(data, length);
}
return data;
} finally {
pollLock.unlock();
}
}
/**
* 若是queue中的元素可用长度[endPosition, length)超过入参length,则不出队列,以备下次使用
* @param data
* @param length
*/
private boolean removeIfOver(@NonNull T data, int length) {
// 未被读取的数据
if (data.getLength() - data.getEndPosition() > length) {
// 大于length只截取[start, end)部分
// 移动被读取的region[start, end)
data.setStartPosition(data.getEndPosition());
data.setEndPosition(data.getEndPosition() + length);
return false;
} else {
data.setStartPosition(data.getEndPosition());
data.setEndPosition(data.getLength());
dataQueue.poll();
updateSize(-data.getLength());
return true;
}
}
/**
* 线程安全的
*
* @param data
*/
public void offer(@NonNull T data) {
if (overflow()) {
return;
}
offerLock.lock();
try {
if (!overflow()) {
dataQueue.offer(data);
updateSize(data.getLength());
} else {
}
} finally {
offerLock.unlock();
}
}
/**
* 清空数据
*/
public void clear() {
dataQueue.clear();
totalSize.set(0);
}
private void updateSize(long size) {
totalSize.addAndGet(size);
}
/**
* true : 满了
*
* @return
*/
private boolean overflow() {
return totalSize.get() >= MAX_SIZE;
}
}
记录一个数据结构
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 前面5篇文章我们讲解了数据结构和算法的一些概述,我们应该对数据结构和算法有了一定的认识了,本篇文章将会带着大家学习...
- 1.数据结构 1. 数据结构的基本术语 数据结构:指的数据对象中的数据元素之间的关系;数据项: 一个数据元素由若干...
- 堆的数据结构能够使得堆顶总是维持最大(对于大根堆)或最小(对于小根堆),给定一个数组,对这个数组进行建堆,则平均复...
- 本文搬运自:https://www.infoq.cn/article/4TCTAeoyvLNK95iuhgom[h...
- 引子 现在维护的一个项目,出现这样一个问题:接口是用php开发的,当有值的时候返回的data是一个键值对,当错误的...