缓存接口定义:
import java.util.Iterator;
/**
* @author lijiaxing
* @Title: GatewayCache
* @ProjectName gateway
* @date 2019/12/4下午4:11
* @Description: 缓存接口
*/
public interface GatewayCache<K, V> {
/**
* 将数据加入到缓存,数据存活时长不做限制
* @param key
* @param value
*/
void put(K key, V value);
/**
* 将数据加入到缓存,数据存活时长为ttl,单位为毫秒
* @param key
* @param value
* @param ttl
*/
void put(K key, V value,long ttl);
/**
* 从缓存中获取数据
* @param key
* @return
*/
V get(K key);
/**
* 从缓存中删除指定的数据
* @param key
*/
void remove(K key);
/**
* 获取当前缓存中数据的总数
* @return
*/
int size();
/**
*
* @return
*/
long sizeof();
/**
* 判断当前缓存是否为空
* @return
*/
boolean isEmpty();
/**
* 判断缓存是否存在
* @param key
* @return
*/
boolean containsKey(K key);
/**
* 清空所有缓存
* @return 被删除数据的个数
*/
int clear();
/**
* 获取缓存Map的迭代器
* @return
*/
Iterator getIterator();
/**
* 根据不同的策略清除缓存中的数据
*/
int reduce(long size);
}
抽象类:
import org.apache.lucene.util.RamUsageEstimator;
import org.aspectj.util.SoftHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author lijiaxing
* @Title: AbstractGatewayCache
* @ProjectName gateway
* @date 2019/12/4下午4:24
* @Description: 抽象缓存类
*/
public abstract class AbstractGatewayCache<K, V> implements GatewayCache<K, V> {
/**
* 缓存,使用软引用,会在内存不够时将缓存回收
*/
public Map<K, CacheDataWrapper<K, V>> cache = new SoftHashMap<>();
/**
* 缓存锁
*/
protected static final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
/**
* 读锁
*/
protected static final ReentrantReadWriteLock.ReadLock readLock = cacheLock.readLock();
/**
* 写锁
*/
protected static final ReentrantReadWriteLock.WriteLock writeLock = cacheLock.writeLock();
/**
* 缓存在堆中占用的最大内存,默认为200MB
*/
protected long maxCacheSize = RamUsageEstimator.ONE_MB * 200;
/**
* 缓存当前所占用的内存大小
*/
protected long currentCacheSize = RamUsageEstimator.sizeOf(this.cache);
@Override
public void put(K key, V value) {
writeLock.lock();
try {
doPut(key, value, -1);
} finally {
writeLock.unlock();
}
}
@Override
public void put(K key, V value, long ttl) {
writeLock.lock();
try {
doPut(key, value, ttl);
} finally {
writeLock.unlock();
}
}
private void doPut(K key, V value, long ttl) {
long current = System.currentTimeMillis();
CacheDataWrapper dataWrapper = new CacheDataWrapper(value, ttl, current, 0);
increaseCurrentCacheSize(dataWrapper);
this.cache.put(key, dataWrapper);
}
/**
*
* @param obj
* @return
*/
private long increaseCurrentCacheSize(Object obj) {
long size = RamUsageEstimator.sizeOf(obj);
while (this.sizeof() + size >= this.maxCacheSize) {
//使用具体的策略清除缓存数据
reduce(size);
}
/**
* 75%
*/
if ((this.sizeof() + size) / this.maxCacheSize > 0.75) {
//异步执行扫描任务,将已过期的数据从缓存中剔除
}
return currentCacheSize += size;
}
@Override
public V get(K key) {
readLock.lock();
CacheDataWrapper<K, V> dataWrapper = null;
try {
dataWrapper = this.cache.get(key);
if (dataWrapper == null) {
return null;
}
} finally {
readLock.unlock();
}
if (dataWrapper.isExpired()) {
this.remove(key);
}
return dataWrapper.get(Boolean.TRUE);
}
@Override
public void remove(K key) {
writeLock.lock();
try {
this.cache.remove(key);
} finally {
writeLock.unlock();
}
}
@Override
public int size() {
readLock.lock();
try {
return this.cache.size();
} finally {
readLock.unlock();
}
}
@Override
public long sizeof() {
readLock.lock();
try {
return RamUsageEstimator.sizeOf(this.cache);
} finally {
readLock.unlock();
}
}
@Override
public boolean isEmpty() {
readLock.lock();
try {
return this.cache.isEmpty();
} finally {
readLock.unlock();
}
}
@Override
public boolean containsKey(K key) {
readLock.lock();
try {
CacheDataWrapper<K, V> dataWrapper = this.cache.get(key);
if (dataWrapper == null) {
return Boolean.FALSE;
}
if (dataWrapper.isExpired()) {
remove(key);
}
} finally {
readLock.unlock();
}
return Boolean.TRUE;
}
@Override
public int clear() {
writeLock.lock();
int total = cache.size();
try {
cache.clear();
} finally {
writeLock.unlock();
}
return total;
}
@Override
public Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> getIterator() {
return this.cache.entrySet().iterator();
}
@Override
public abstract int reduce(long size);
@Override
public String toString() {
String s = "GatewayCache{\n";
Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> iterator = getIterator();
while (iterator.hasNext()) {
Map.Entry<K, CacheDataWrapper<K, V>> next = iterator.next();
K key = next.getKey();
CacheDataWrapper<K, V> value = next.getValue();
s = s + key + "->" + value + "\n";
}
return s + "}";
}
}
缓存对象:
public class CacheDataWrapper<K, V> {
/**
* 缓存的值
*/
private V value;
/**
* 缓存对象存活时间
* 默认为 0
* 已过期则为-1
*/
private long ttl;
/**
* 上次访问的时间(时间戳)
*/
private long lastAccessTime;
/**
* 访问次数
*/
private int accessCount;
public CacheDataWrapper(V value, long ttl, long lastAccessTime, Integer accessCount) {
this.value = value;
this.ttl = ttl;
this.lastAccessTime = lastAccessTime;
this.accessCount = accessCount;
}
/**
* 判断当前缓存对象是否过期
*
* @return
*/
public boolean isExpired() {
Boolean expired = Boolean.FALSE;
if (ttl > 0) {
expired = System.currentTimeMillis() - lastAccessTime > ttl;
}
return expired;
}
/**
* @return
*/
public V get() {
return value;
}
/**
* @param updateExpiringTime 是否刷新过期时间
* @return
*/
public V get(Boolean updateExpiringTime) {
if(updateExpiringTime){
this.lastAccessTime = System.currentTimeMillis();
}
accessCount++;
return get();
}
public int getAccessCount() {
return accessCount;
}
@Override
public String toString() {
return "CacheDataWrapper{" +
"value=" + value +
", ttl=" + ttl +
", lastAccessTime=" + lastAccessTime +
", accessCount=" + accessCount +
'}';
}
}
具体实现:
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @author lijiaxing
* @Title: GatewayLocalCache
* @ProjectName gateway
* @date 2019/12/5下午3:20
* @Description: 缓存淘汰策略使用LFU(Least Frequently Used) ,即最近最少使用
* <p>
* 如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。
* 因此,当空间满时,最小频率访问的数据最先被淘汰。
*/
public class GatewayLocalCache<K, V> extends AbstractGatewayCache<K, V> {
/**
* @param maxCacheSize 缓存最大所占用的内存空间
* <p>
* n * RamUsageEstimator.ONE_KB; 表示nK大小
* n * RamUsageEstimator.ONE_MB; 表示nM大小
* n * RamUsageEstimator.ONE_GB; 表示nG大小
*/
public GatewayLocalCache(long maxCacheSize) {
super.maxCacheSize = maxCacheSize;
}
/**
* 使用缓存最大所占用的内存空间的默认值,即500MB
*/
public GatewayLocalCache() {
}
private int minAccessCount = 0;
@Override
public int reduce(long size) {
int count = 0;
Iterator<Map.Entry<K, CacheDataWrapper<K, V>>> iterator = super.getIterator();
while (iterator.hasNext()) {
Map.Entry<K, CacheDataWrapper<K, V>> next = iterator.next();
CacheDataWrapper<K, V> dataWrapper = next.getValue();
boolean expired = dataWrapper.isExpired();
if (expired) {
super.remove(next.getKey());
count++;
}
if (minAccessCount == 0 || dataWrapper.getAccessCount() < minAccessCount)
minAccessCount = dataWrapper.getAccessCount();
}
/**
* 有过期数据被处理的情况不执行下面代码
*
* 遍历缓存中的数据,使缓存中每一个CacheDataWrapper的accessCount值都减minAccessCount
* 目的是保证公平
*/
if (super.sizeof() + size > super.maxCacheSize) {
Set<Map.Entry<K, CacheDataWrapper<K, V>>> entries = super.cache.entrySet();
for (Map.Entry<K, CacheDataWrapper<K, V>> entry : entries) {
CacheDataWrapper<K, V> dataWrapper = entry.getValue();
if (dataWrapper.getAccessCount() - minAccessCount <= 0) {
writeLock.lock();
try {
this.cache.remove(entry.getKey());
} finally {
writeLock.unlock();
}
count++;
}
}
}
return count;
}
}