写点什么

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
用户头像

kenny

关注

还未添加个人签名 2020.08.26 加入

还未添加个人简介

评论

发布
暂无评论
Mybatis中LRU缓存实现_mybatis_kenny_InfoQ写作社区