LRU算法算是个常见的算法,很有必要去了解它,现在我们就来看看什么是 LRU
LRU 的全称是 Least Recently Used(最近最少使用),就如它的含义一样,最近最少使用的。在实际的场景中大多会把它当作一种 淘汰策略
它的应用场景也很简单,我们的存储空间总是有限的,一旦超过了最大限度就必须要淘汰一些数据,那淘汰哪种数据才算是合理的呢?合理的方式有很多,不同的场景也不一样,但淘汰 最近最少使用的数据,在绝大部分场景下都是合理的,所以LRU算法很常见。
redis的6大淘汰策略里面就有2种是 LRU策略
关于MyBatis的缓存可以参看这篇文章 https://blog.csdn.net/Tomwildboar/article/details/127570765
MyBatis的二级缓存各种功能实现是基于 装饰器模式来实现的,默认就是 LRU
下面是MyBatis 的 LruCache源码, 因为比较少就全部粘贴了
package org.apache.ibatis.cache.decorators;import java.util.LinkedHashMap;
import java.util.Map;import org.apache.ibatis.cache.Cache;/*** Lru (least recently used) cache decorator.** @author Clinton Begin*/
public class LruCache implements Cache {private final Cache delegate;private Map
它里面主要有两个操作
removeEldestEntry
LinkedHashMap 底层也还是基于HashMap的,并且没有重写 put方法,是直接调用的 HashMap的put方法
在HashMap的put方法里面最后会去调用 afterNodeInsertion 方法, LinkedHashMap 里面重写了这个方法如下, evict 默认就是 true
这个方法的描述 possibly remove eldest ,可能移除最老的(也就是 first),当if判断是ture的时候就会删除这个元素
void afterNodeInsertion(boolean evict) { // possibly remove eldestLinkedHashMap.Entry first;if (evict && (first = head) != null && removeEldestEntry(first)) {K key = first.key;removeNode(hash(key), key, null, false, true);}
}
我们再来看看重写后的 removeEldestEntry ,eldest 通过上面其实就是链表头第一个元素
keyMap = new LinkedHashMap(size, .75F, true) {private static final long serialVersionUID = 4267176411845948333L;@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {boolean tooBig = size() > size;if (tooBig) {eldestKey = eldest.getKey();}return tooBig;}
};
如果当前容器里面的数据大于规定的容量,就执行 eldestKey = eldest.getKey();
cycleKeyList
添加元素的时候会调用这个方法
private void cycleKeyList(Object key) {keyMap.put(key, key);if (eldestKey != null) {delegate.removeObject(eldestKey);eldestKey = null;}
}
上面我们知道,当元素大于容量规定大小,eldestKey 就会等于第一个元素的key,这时候就会删掉这个元素,从而实现 LRU策略
上面这种LRU策略,在某种情况下会存在漏洞,如果我们每次都是淘汰第一个元素,那如果我们在查询到元素A后就一直不再使用它了,这样它从链表尾到链表尾才会被淘汰,但是我们有一个元素B在它的后面但是经常被使用,但元素B依旧比元素A先淘汰,这样就不合理了。
MySQL 操作数据的时候先会把数据加载到内存中(Buffer Pool),但是内存的大小是有限的,所以也就存在了淘汰策略,如果只是简单的使用LRU策略,就会存在上述的问题。
MySQL对LRU策略进行了改造来完善这个问题,完整的buffer pool 参看这里 https://blog.csdn.net/Tomwildboar/article/details/121525187
它的逻辑也很简单