com.gitee.apanlh.util.cache.local.CacheLruTwoQ Maven / Gradle / Ivy
package com.gitee.apanlh.util.cache.local;
import com.gitee.apanlh.util.base.Empty;
import com.gitee.apanlh.util.valid.ValidParam;
/**
* CacheTwoQ
*
CacheLRU-2(Two queues 2Q)
*
历史队列(采用FIFO的淘汰策略)和缓存队列(采用LRU-1的淘汰策略)
*
新访问的数据插入到FIFO队列
*
如果数据在FIFO队列中一直没有被再次访问,则最终按照FIFO规则淘汰
*
如果数据在FIFO队列中被再次访问,则将数据移到LRU队列
*
如果数据在LRU队列再次被访问,则将数据移到LRU队尾
*
超出既定长度则 LRU队列淘汰中队头数据
*
* @author Pan
*/
public class CacheLruTwoQ extends CacheAbstract {
/** FIFO队列 */
private CacheFifo> a1;
/** LRU队列 */
private CacheLru> a2;
/** 命中次数 */
private int hit;
/**
* 默认构造函数
*
默认256最大容量
*
* @author Pan
*/
public CacheLruTwoQ() {
this(256, 256);
}
/**
* 构造函数
*
默认A1与A2容量一致
*
自定义容量
*
* @author Pan
* @param capacity 容量
*/
public CacheLruTwoQ(int capacity) {
this(capacity, capacity);
}
/**
* 构造函数
*
自定义FIFO,LRU长度
*
A1比例大则命中率降低,A1比例小则数据时间变长
*
* @author Pan
* @param a1Capacity a1容量
* @param a2Capacity a2容量
*/
public CacheLruTwoQ(int a1Capacity, int a2Capacity) {
super(Empty.map());
this.a1 = new CacheFifo<>(a1Capacity);
this.a2 = new CacheLru<>(a2Capacity);
}
/**
* 添加值
*
新访问的数据插入到FIFO队列(a1) 插入队尾;
*
* @author Pan
* @param key 键
* @param value 值
* @return V
*/
@Override
V putHandler(K key, V value) {
CacheObject a2CacheObject = a2.getUnlocked(key);
// 避免key值一样获取到的缓存数据为旧缓存
if (ValidParam.isNotNull(a2CacheObject)) {
a2CacheObject.setData(value);
} else {
this.a1.putUnlocked(key, new CacheObject<>(value));
}
return null;
}
@Override
V getHandler(K key, V value) {
// 优先对LRU检索
V v = getA2(key);
// 二次检查
return v == null ? getA1(key) : v;
}
/**
* 获取A1缓存数据
*
* @author Pan
* @param key 键
* @return V
*/
V getA1(K key) {
CacheObject v = this.a1.getUnlocked(key);
if (v == null) {
return null;
}
hit++;
// 删除FIFO中数据
this.a1.removeUnlocked(key);
// 如果数据在FIFO队列中被再次访问,默认将数据移到LRU队列插入队尾
this.a2.putUnlocked(key, v);
return v.getData();
}
/**
* 获取A2缓存数据
*
* @author Pan
* @param key 键
* @return V
*/
V getA2(K key) {
CacheObject v = this.a2.getUnlocked(key);
if (v == null) {
return null;
}
hit++;
return v.getData();
}
/**
* 清理A1缓存及A2缓存
*
两者缓存都会清空
*
* @author Pan
*/
@Override
public void clear() {
lock(this::clearUnlock);
}
@Override
public void clearUnlock() {
a1.clearUnlock();
a2.clearUnlock();
}
/**
* 获取总长度
*
* @author Pan
* @return int
*/
@Override
public int size() {
return getA1Size() + getA2Size();
}
/**
* 获取a1长度
*
* @author Pan
* @return int
*/
public int getA1Size() {
return this.a1.size();
}
/**
* 获取a2长度
*
* @author Pan
* @return int
*/
public int getA2Size() {
return this.a2.size();
}
/**
* 获取FIFO缓存命中次数
*
* @author Pan
* @return int
*/
public int getA1Hit() {
return this.a1.getHit();
}
/**
* 获取LRU缓存命中次数
*
* @author Pan
* @return int
*/
public int getA2Hit() {
return this.a2.getHit();
}
/**
* 获取TwoQ缓存命中次数
*
非FIFO+LRU的缓存次数
*
* @author Pan
* @return int
*/
@Override
public int getHit() {
return this.hit;
}
/**
* 获取A1缓存
*
* @author Pan
* @return CacheFifo
*/
public CacheFifo> getA1() {
return this.a1;
}
/**
* 获取A2缓存
*
* @author Pan
* @return CacheLru
*/
public CacheLru> getA2() {
return this.a2;
}
@Override
public String toString() {
return "LRU2[FIFO=" + this.a1 + ", LRU=" + this.a2 + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
CacheLruTwoQ, ?> that = (CacheLruTwoQ, ?>) o;
if (!a1.equals(that.a1)) return false;
return a2.equals(that.a2);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + a1.hashCode();
result = 31 * result + a2.hashCode();
return result;
}
}