Mybatis 中 LRU 缓存实现
作者:kenny
- 2022 年 7 月 26 日
本文字数:2133 字
阅读完需:约 7 分钟
LRU 缓存淘汰是一种常用的置换数据策略。全称是 Least Recently Used,一般认为最近使用过的数据应该是是「有用的」,很久都没用过的数据应该是无用的,当内存满了之后应该优先删那些很久没用过的数据。
Cache 接口
public interface Cache {
/**
* 缓存唯一标识
* @return
*/
Long getId();
/**
* 新增键值对
* @param key
* @param value
*/
void putObject(Object key, Object value);
/**
* 移除键值对
* @param key
* @return
*/
Object removeObject(Object key);
/**
* 获取值
* @param key
* @return
*/
Object getObject(Object key);
/**
* 清空缓存
*/
void clear();
/**
* 获取当前缓存大小
* @return
*/
int getSize();
/**
* Any locking needed by the cache must be provided internally by the cache provider.
* @return
*/
default ReadWriteLock getReadWriteLock() {
return null;
}
}
复制代码
Cache 缓存实现类
public class PerpetualCache implements Cache {
private final Long id;
private final Map<Object, Object> cache = new HashMap<>(); //简单的本地Map缓存
public PerpetualCache(Long id) {
this.id = id;
}
@Override
public Long getId() {
return id;
}
@Override
public int getSize() {
return cache.size();
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return Cache.super.getReadWriteLock();
}
@Override
public boolean equals(Object o) {
if (getId() == null) {
throw new RuntimeException("Cache instances require an ID.");
}
if (this == o) {
return true;
}
if (!(o instanceof Cache)) {
return false;
}
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new RuntimeException("Cache instances require an ID.");
}
return getId().hashCode();
}
}
复制代码
LRU 缓存实现类,使用装饰模式 + LinkedHashMap 实现
public class LRUCache implements Cache{
private Cache delegate; //装饰模式,用来存放任意实现Cache接口的对象
private Map<Object, Object> keyMap; //LinkedHashMap对象,通过它的特性实现LRU策略
private Object eldestKey; //超过容量时淘汰的对象引用
LRUCache(Cache cache){
this.delegate = cache;
setSize(1024); //默认1024,当put第1025个元素时,会淘汰缓冲的一个元素
}
public void setSize(final int size){
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L;
@Override
/**
* 当put进新的值方法返回true时,便移除该map中最老的键和值
*/
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean big = size() > size;
if (big){
eldestKey = eldest.getKey();
}
return big;
}
};
}
@Override
public Long getId() {
return delegate.getId();
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public Object getObject(Object key) {
keyMap.get(key); // touch
return delegate.getObject(key);
}
@Override
public void clear() {
delegate.clear();
keyMap.clear();
}
@Override
public int getSize() {
return delegate.getSize();
}
/**
* 当存在淘汰元素时,从Map中移除
* @param key
*/
public void cycleKeyList(Object key){
keyMap.put(key, key); //这里的value,放的是key值?是为了避免错误的修改引用的值吗?
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3
版权声明: 本文为 InfoQ 作者【kenny】的原创文章。
原文链接:【http://xie.infoq.cn/article/30acdfe25accd6e4f7ad63f88】。文章转载请联系作者。
kenny
关注
还未添加个人签名 2020.08.26 加入
还未添加个人简介
评论