LRU算法
LRU(The Least Recently Used)最近最少使用。
LRU算法的思想
如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。
因此,当空间满时,最久未被使用的数据最先被淘汰。
LRU算法的描述
设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:
-
put(key, value)
将记录(key, value)插入该结构。当缓存满时,将最久未使用的数据淘汰掉。 -
get(key)
返回key对应的value值。
LRU算法的实现
-
最朴素的思想就是用数组+时间戳的方式,不过这样做效率较低。
-
我们可以用双向链表(LinkedList)+哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找)。
-
直接使用Java里有的数据结构
LinkedHashMap
。
LRUCache
package com.itplh;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author: tanpenggood
* @date: 2020-09-17 10:49
*/
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private int cacheSize;
public LRUCache(int cacheSize) {
// LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
// 关键:使用的三个参数的构造方法,将accessOrder设置为true,LinkedHashMap默认为false
super(16, (float) 0.75, true);
this.cacheSize = cacheSize;
}
/**
* 当缓存空间不够时,淘汰最久未使用的数据
*
*/
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > cacheSize;
}
}
LRUCacheTest
package com.itplh;
import lombok.extern.slf4j.Slf4j;
/**
* @author: tanpenggood
* @date: 2020-09-17 10:49
*/
@Slf4j
public class LRUCacheTest {
public static void main(String[] args) {
LRUCache<String, Integer> cache = new LRUCache<>(5);
for (int i = 1; i <= 5; i++) {
cache.put("k" + i, i);
}
log.info("all cache: {}", cache);
cache.get("k3");
log.info("get k3: {}", cache);
cache.get("k4");
log.info("get k4: {}", cache);
cache.get("k4");
log.info("get k4: {}", cache);
cache.put("k" + 10, 10);
log.info("After running the LRU algorithm cache: {}", cache);
}
}
Output
all cache: {
k1=1, k2=2, k3=3, k4=4, k5=5}
get k3: {
k1=1, k2=2, k4=4, k5=5, k3=3}
get k4: {
k1=1, k2=2, k5=5, k3=3, k4=4}
get k4: {
k1=1, k2=2, k5=5, k3=3, k4=4}
After running the LRU algorithm cache: {
k2=2, k5=5, k3=3, k4=4, k10=10}
总结
- 每一次从
cache
中get
数据时会将取出来的元素移到队尾。 - 向
cache
中put
数据时,先将新数据存到队尾,再判断缓存空间是否够用,若空间不够,则淘汰队首(最久未使用)的元素。